Compare commits

..

1 commit

Author SHA1 Message Date
537dde170b (timer): basic start 2026-02-16 17:41:07 +00:00
10 changed files with 47 additions and 224 deletions

View file

@ -4,10 +4,10 @@
.global trap_entry
trap_entry:
# Allocate stack space for GPRs (256 bytes) + FPU registers (512 bytes)
addi sp, sp, -768 # Total: 256 (GPRs) + 512 (FPU)
# Create space on the stack for 32 registers (32 * 8 = 256 bytes)
addi sp, sp, -256
# --- Save GPRs ---
# Save all General Purpose Registers (GPRs)
sd ra, 0(sp)
sd gp, 8(sp)
sd tp, 16(sp)
@ -39,112 +39,19 @@ trap_entry:
sd t5, 224(sp)
sd t6, 232(sp)
# --- Save mepc/mcause/mstatus ---
# Save mepc to the stack (using offset 240)
csrr t0, mepc
sd t0, 240(sp)
csrr t0, mcause
sd t0, 248(sp)
csrr t0, mstatus
sd t0, 256(sp)
# --- Check FPU Status (mstatus.FS) ---
csrr t1, mstatus
li t2, 0x6000
and t1, t1, t2
bnez t1, save_fpu
# If no FPU, skip to handler
j call_handler
save_fpu:
# Save FPU registers (f0-f31) starting at offset 256
fsd f0, 256(sp)
fsd f1, 264(sp)
fsd f2, 272(sp)
fsd f3, 280(sp)
fsd f4, 288(sp)
fsd f5, 296(sp)
fsd f6, 304(sp)
fsd f7, 312(sp)
fsd f8, 320(sp)
fsd f9, 328(sp)
fsd f10, 336(sp)
fsd f11, 344(sp)
fsd f12, 352(sp)
fsd f13, 360(sp)
fsd f14, 368(sp)
fsd f15, 376(sp)
fsd f16, 384(sp)
fsd f17, 392(sp)
fsd f18, 400(sp)
fsd f19, 408(sp)
fsd f20, 416(sp)
fsd f21, 424(sp)
fsd f22, 432(sp)
fsd f23, 440(sp)
fsd f24, 448(sp)
fsd f25, 456(sp)
fsd f26, 464(sp)
fsd f27, 472(sp)
fsd f28, 480(sp)
fsd f29, 488(sp)
fsd f30, 496(sp)
fsd f31, 504(sp)
call_handler:
# Pass stack pointer to C handler
mv a0, sp
# Call trap handler
mv a0, sp # put the stack pointer to the first arg
call handle_trap
# --- Restore mepc ---
# restore mepc
ld t0, 240(sp)
csrw mepc, t0
# --- Restore FPU (if it was saved) ---
csrr t1, mstatus
li t2, 0x6000
and t1, t1, t2
bnez t1, restore_fpu
j restore_gpr
restore_fpu:
# Restore FPU registers
fld f0, 256(sp)
fld f1, 264(sp)
fld f2, 272(sp)
fld f3, 280(sp)
fld f4, 288(sp)
fld f5, 296(sp)
fld f6, 304(sp)
fld f7, 312(sp)
fld f8, 320(sp)
fld f9, 328(sp)
fld f10, 336(sp)
fld f11, 344(sp)
fld f12, 352(sp)
fld f13, 360(sp)
fld f14, 368(sp)
fld f15, 376(sp)
fld f16, 384(sp)
fld f17, 392(sp)
fld f18, 400(sp)
fld f19, 408(sp)
fld f20, 416(sp)
fld f21, 424(sp)
fld f22, 432(sp)
fld f23, 440(sp)
fld f24, 448(sp)
fld f25, 456(sp)
fld f26, 464(sp)
fld f27, 472(sp)
fld f28, 480(sp)
fld f29, 488(sp)
fld f30, 496(sp)
fld f31, 504(sp)
restore_gpr:
# Restore GPRs
# Restore all GPRs
ld ra, 0(sp)
ld gp, 8(sp)
ld tp, 16(sp)
@ -176,6 +83,8 @@ restore_gpr:
ld t5, 224(sp)
ld t6, 232(sp)
# Restore stack pointer
addi sp, sp, 768
# Shrink the stack back
addi sp, sp, 256
# Return from Machine-mode trap
mret

View file

@ -137,8 +137,7 @@ void kprintf_internal(const char *format, va_list args)
if (*p == '%')
{
p++;
if (*p == '\0')
break;
if(*p == '\0') break;
switch (*p)
{
case 'c':
@ -150,8 +149,7 @@ void kprintf_internal(const char *format, va_list args)
case 's':
{
char *s = va_arg(args, char *);
if (!s)
s = "(null)";
if (!s) s = "(null)";
kprint(s);
break;
}
@ -161,12 +159,12 @@ void kprintf_internal(const char *format, va_list args)
kprint_int(d);
break;
}
case 'u':
{
case 'u':
{
unsigned int u = va_arg(args, unsigned int);
kprint_int((int)u);
break;
}
}
case 'f':
{
double f = va_arg(args, double);
@ -176,11 +174,11 @@ void kprintf_internal(const char *format, va_list args)
case 'x': // Hex
case 'p': // Pointer
{
#if UINTPTR_MAX == 0xffffffffULL
unsigned int x = va_arg(args, unsigned int);
#else
uint64_t x = va_arg(args, uint64_t);
#endif
#if UINTPTR_MAX == 0xffffffffULL
unsigned int x = va_arg(args, unsigned int);
#else
uint64_t x = va_arg(args, uint64_t);
#endif
kprint_hex(x);
break;
}

View file

@ -8,7 +8,6 @@
#include <kernel/memory.h>
#include <kernel/timer.h>
void interrupt_init()
{
kprint("Initialising Interrupts...");
@ -23,17 +22,6 @@ void interrupt_init()
mie_val |= (1 << MIE_BIT_MEIE) | (1 << MIE_BIT_MTIE);
asm volatile("csrw mie, %0" ::"r"(mie_val));
kputs("OK");
uint32_t mie, sie, mstatus;
asm volatile ("csrr %0, mie" : "=r"(mie));
asm volatile ("csrr %0, sie" : "=r"(sie));
asm volatile ("csrr %0, mstatus" : "=r"(mstatus));
kprintf("mie: 0x%X, sie: 0x%X, mstatus: 0x%X\n", mie, sie, mstatus);
// Enable timer and global interrupts
asm volatile ("csrs mie, %0" : : "r"(mie | (1 << 7) | (1 << 3))); // Enable timer and global
asm volatile ("csrs sie, %0" : : "r"(sie | (1 << 7) | (1 << 3))); // Enable timer and global
asm volatile ("csrs mstatus, %0" : : "r"(mstatus | (1 << 3))); // Set MIE bit
}
void kpanic(const char *reason, ...)
@ -67,11 +55,15 @@ void kpanic_force()
void handle_trap(trap_frame_t *registers)
{
// Read the 'mcause' register to see WHY we trapped
unsigned long cause;
__asm__ volatile("csrr %0, mcause" : "=r"(cause));
// Check if the top bit is 1 (Interrupt) or 0 (Exception)
// For 64-bit RISC-V, the bit is 63
int is_interrupt = (registers->mcause >> 63) & 1;
int is_interrupt = (cause >> 63) & 1;
unsigned long code = registers->mcause & 0xfff;
unsigned long code = cause & 0xfff;
if (is_interrupt)
{
@ -86,7 +78,7 @@ void handle_trap(trap_frame_t *registers)
kprintf("\n[EXCEPTION] Code: %d | Instruction: %x | Fault Address: %x\n", code, registers->mepc, mtval);
switch (registers->mcause)
switch (cause)
{
case 0:
kpanic("Reason: Instruction Address Misaligned\n");
@ -113,7 +105,7 @@ void handle_trap(trap_frame_t *registers)
kpanic("Reason: Store/AMO Access Fault\n");
break;
default:
kpanic("Reason: Unknown Exception Code %d\n", registers->mcause);
kpanic("Reason: Unknown Exception Code %d\n", cause);
break;
}
}
@ -124,7 +116,8 @@ void handle_interrupt(unsigned long code)
switch (code)
{
case 7:
timer_tick();
timer_handle_interrupt();
break;
case 11:
volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM(0);

View file

@ -3,8 +3,6 @@
#define MSTATUS 0x300
#define MIE 0x304
#define MCAUSE 0x342
#define MEPC 0x341
#define MSTATUS_BIT_MIE 3
#define MIE_BIT_MTIE 7
#define MIE_BIT_MEIE 11
@ -58,10 +56,8 @@ typedef struct {
uint64_t t5; // x30
uint64_t t6; // x31
// Control and Status Register state (Saved in traps.S)
uint64_t mepc; // offset 240
uint64_t mcause; // offset 248
uint64_t mstatus; // offset 256
// Control and Status Register state
uint64_t mepc; // offset 240 (Saved in traps.S)
} trap_frame_t;
void interrupt_init();

View file

@ -5,13 +5,11 @@
#include <kernel/plic.h>
#include <kernel/interrupts.h>
#include <kernel/memory.h>
#include <kernel/timer.h>
void kmain()
{
zero_bss();
plic_init();
timer_init();
uart_init();
page_init();
interrupt_init();
@ -19,12 +17,4 @@ void kmain()
kprintf("Hello, from %s!", "SquidgeOS");
kputs("----------------------");
knewline();
while (1) {
uint64_t ticks = timer_get_ms();
kputchar('T');
kputchar(':'); // Print "T:1234" every second
kprint_int(ticks);
knewline();
delay_ms(1000);
}
}

View file

@ -13,13 +13,7 @@ void plic_init()
// This is a bitmask, so we shift 1 by the IRQ number.
*PLIC_ENABLE(hart) = (1 << UART_IRQ);
// Set priority for CLINT timer interrupt (IRQ 7)
*PLIC_PRIORITY(TIMER_IRQ) = 1; // Lowest priority
// Enable CLINT timer interrupt for Hart 0
*PLIC_ENABLE(hart) |= (1 << TIMER_IRQ);
// 3. Set the priority threshold for Hart 0
// We set this to 0 so that ANY interrupt with priority > 0 gets through.
*PLIC_THRESHOLD(hart) = 0;
}
}

View file

@ -16,7 +16,6 @@
#define PLIC_CLAIM(hart) ((volatile uint32_t *)(PLIC_BASE + 0x200004 + (hart) * 0x1000))
#define UART_IRQ 10
#define TIMER_IRQ 7
void plic_init();

View file

@ -1,43 +1,12 @@
#include <stdint.h>
#include <stddef.h>
#include "timer.h"
#include "plic.h"
#include "interrupts.h"
#include "drivers/uart.h"
#include <kernel/interrupts.h>
#include <kernel/plic.h>
#include <kernel/timer.h>
_Atomic uint64_t sys_ticks = 0;
const uint64_t tick_delta = TICKS_PER_MS;
void timer_handle_interrupt()
{
static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME;
static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0);
void timer_init() {
timer_tick();
}
void timer_tick() {
static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME;
static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0);
uint64_t current_mtime = *mtime;
uint64_t new_mtimecmp = current_mtime + tick_delta;
*mtimecmp = new_mtimecmp;
//kprintf("Set mtimecmp: %u (mtime: %u, delta: %u)\n", new_mtimecmp, current_mtime, tick_delta);
sys_ticks++;
}
// Get current time in milliseconds
uint64_t timer_get_ms() {
return sys_ticks;
}
// Delay for 'ms' milliseconds (blocking)
void delay_ms(uint64_t ms) {
if (ms == 0) return;
uint64_t end = sys_ticks + ms;
while (sys_ticks < end) {
asm volatile("wfi");
}
}
// Sleep for 'ms' milliseconds (non-blocking, if possible)
// For now, just call delay_ms (can be improved later)
void sleep_ms(uint64_t ms) {
delay_ms(ms);
*mtimecmp = *mtime + TIMER_FREQ;
}

View file

@ -1,30 +1,8 @@
#ifndef TIMER_H
#define TIMER_H
#include <stdint.h>
#ifndef KTIMER_H
#define KTIMER_H
/* Define your clock frequency here based on your hardware */
/* Example: 12.5 MHz for QEMU virt machine */
#define CLOCK_FREQ_HZ 12500000
#define TIMER_FREQ 100000
/* Calculate ticks per millisecond */
#define TICKS_PER_MS (CLOCK_FREQ_HZ / 1000)
extern _Atomic uint64_t sys_ticks;
extern const uint64_t tick_delta;
// Initialize timer (1ms ticks)
void timer_init();
// Increment the system tick counter
void timer_tick();
// Get current time in milliseconds
uint64_t timer_get_ms();
// Delay for 'ms' milliseconds (blocking)
void delay_ms(uint64_t ms);
// Sleep for 'ms' milliseconds (non-blocking, if possible)
void sleep_ms(uint64_t ms);
void timer_handle_interrupt();
#endif

View file

@ -2,8 +2,5 @@
#define STRING_H
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
int strcmp(const char *str1, const char *str2);
size_t strlen(const char *s);
#endif