os/mm.c \
os/panic.c \
os/thread.c \
+ os/time.c \
rcp/vi.c \
)
@echo $(call FIXPATH,"Assembling: libn64/$<")
@$(CC) -x assembler-with-cpp $(CFLAGS) $(OPTFLAGS) -MMD -c $< -o $@
-%.o: %.c
+%.o: %.c include/syscall.h
@echo $(call FIXPATH,"Compiling: libn64/$<")
@$(CC) $(CFLAGS) $(OPTFLAGS) -MMD -c $< -o $@
#define LIBN64_SYSCALL_THREAD_UNREG_INTR 4
#define LIBN64_SYSCALL_PAGE_ALLOC 5
#define LIBN64_SYSCALL_PAGE_FREE 6
+#define LIBN64_SYSCALL_TIME 7
-#define LIBN64_SYSCALL_SEND_MESSAGE 7
-#define LIBN64_SYSCALL_RECV_MESSAGE 8
-#define LIBN64_SYSCALL_INVALID 9
+#define LIBN64_SYSCALL_SEND_MESSAGE 8
+#define LIBN64_SYSCALL_RECV_MESSAGE 9
+#define LIBN64_SYSCALL_INVALID 10
#ifndef __ASSEMBLER__
#include <stdint.h>
+#include <time.h>
enum libn64_interrupt {
LIBN64_INTERRUPT_AI = 0x430,
);
}
+// Returns a timeval struct corresponding to the time elapsed since boot.
+libn64func __attribute__((always_inline))
+static inline struct timeval libn64_time(void) {
+ struct timeval time;
+ register uint32_t v0 __asm__("$v0");
+ register uint32_t v1 __asm__("$v1");
+
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".set noat\n\t"
+ "li $at, %2\n\t"
+ "syscall\n\t"
+ ".set reorder\n\t"
+ ".set at\n\t"
+
+ : "=r" (v0), "=r" (v1)
+ : "K" (LIBN64_SYSCALL_TIME)
+ : "memory"
+ );
+
+ time.tv_sec = v0;
+ time.tv_usec = v1;
+ return time;
+}
+
// Sends a message with no parameter values to the specified thread.
libn64func __attribute__((always_inline))
static inline void libn64_send_message(libn64_thread thread, uint32_t message) {
--- /dev/null
+//
+// libn64/include/time.h: time.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef LIBN64_INCLUDE_TIME_H
+#define LIBN64_INCLUDE_TIME_H
+
+#include <stdint.h>
+
+struct timeval {
+ uint32_t tv_sec;
+ uint32_t tv_usec;
+};
+
+#endif
+
bne $k1, $zero, libn64_exception_handler_rcp_interrupt
andi $k1, $k0, 0x8000
bne $k1, $zero, libn64_exception_handler_timer_interrupt
- andi $k1, $k0, 0x0800
- beql $k1, $zero, libn64_panic
- addu $k0, $zero, $zero
+ nop
# We got an unexpected interrupt. Since we don't know how to handle it, panic.
# Currently, this will happen for software interrupts and the Indy debugger-
j libn64_panic
addu $k0, $zero, $zero
-# A timer interrupt occurred. Bounce the compare register to silence it.
-# In the future, we probably want to pump a message out on a message queue
-# or something here to acknowledge that a timer interrupt occurred.
+# A timer interrupt occurred. Bounce the compare register to silence it
+# and increment the "rollover" counter that we use to track time.
libn64_exception_handler_timer_interrupt:
- mfc1 $k1, $11
- mtc1 $k1, $11
+ mfc0 $k1, $11
+ mtc0 $k1, $11
+ lui $k0, 0x8000
+ lw $k1, 0x448($k0)
+ addiu $k1, $k1, 0x1
+ sw $k1, 0x448($k0)
eret
# Handle a RCP interrupt: pump messages out to the listeners.
lw $a0, 0x01C($k1)
mtc0 $a1, $14
- addiu $at, $zero, 0x403
+ xori $at, $zero, 0x8403
mtc0 $at, $12
srl $at, $k1, 0x9
andi $at, $at, 0xFF
.size libn64_syscall_page_free,.-libn64_syscall_page_free
# -------------------------------------------------------------------
+# libn64::time
+#
+# TODO: Preserve HI and LO registers.
+# -------------------------------------------------------------------
+.type libn64_syscall_time, @function
+.align 5
+libn64_syscall_time:
+ lui $k0, 0x8000
+ ld $k0, 0x448($k0)
+ mtc0 $k1, $14
+ dmfc0 $k1, $9
+ or $k0, $k0, $k1
+
+ # 62,500,000 * 1.5 / 2 = 46,875,000 ticks per second.
+ lui $k1, 0x02CB
+ ori $k1, 0x4178
+ ddivu $k0, $k1
+
+ # tv_sec is the result of the div. Compute tv_usec next.
+ mflo $v0 # div result -> tv_sec
+ mfhi $v1 # mod result * 1e6
+ lui $k0, 0x000F
+ ori $k0, 0x4240
+ multu $v1, $k0
+
+ mfhi $v1
+ mflo $k0
+ dsll32 $k0, $k0, 0
+ dsll32 $v1, $v1, 0
+ dsrl32 $k0, $k0, 0
+ or $v1, $v1, $k0
+ ddivu $v1, $k1
+ mflo $v1
+ nop
+ eret
+
+.size libn64_syscall_time,.-libn64_syscall_time
+
+# -------------------------------------------------------------------
# libn64::send_message
# $a0 = recipient
# $a1 = message
.long libn64_syscall_thread_unreg_intr
.long libn64_syscall_page_alloc
.long libn64_syscall_page_free
+.long libn64_syscall_time
.long libn64_syscall_send_message
.long libn64_syscall_recv_message
#include <os/idle_thread.h>
#include <os/mm.h>
#include <os/thread.h>
+#include <os/time.h>
#include <stddef.h>
#include <syscall.h>
// Entry point (invoked from IPL handler).
libn64func __attribute__((noreturn))
void libn64_main(uint32_t kernel_sp, uint32_t bss_end) {
+
+ // Initialize critical subsystems.
+ libn64_time_init();
libn64_thread_early_init(kernel_sp);
// Give libn64 the minimum amount of memory allowable (~24KiB)
"srl $at, %0, 0x9\n\t"
"andi $at, $at, 0xFF\n\t"
"mtc0 $at, $10\n\t"
- "addiu $at, $zero, 0x401\n\t"
+ "xori $at, $zero, 0x8401\n\t"
"mtc0 $at, $12\n\t"
".set reorder\n\t"
".set at\n\t"
--- /dev/null
+//
+// libn64/os/time.c: OS time functions.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include <libn64.h>
+
+// Initialize the time subsystem.
+void libn64_time_init(void) {
+
+ // Bounce the timer so that it starts firing.
+ // Initialize the global time counter to zero.
+ __asm__ __volatile__(
+ ".set noat\n\t"
+ ".set gp=64\n\t"
+ "addiu $at, $zero, -0x1\n\t"
+ "mtc0 $at, $11\n\t"
+ "mtc0 $zero, $9\n\t"
+ "lui $at, 0x8000\n\t"
+ "sd $zero, 0x448($at)\n\t"
+ ".set gp=default\n\t"
+ ".set at\n\t"
+ );
+}
+
--- /dev/null
+//
+// libn64/priv_include/os/time.h: OS time definitions.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef LIBN64_PRIV_INCLUDE_OS_TIME_H
+#define LIBN64_PRIV_INCLUDE_OS_TIME_H
+
+#include <libn64.h>
+
+// Initializes the time subsystem.
+libn64func
+void libn64_time_init(void);
+
+#endif
+