Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
kernel.hh
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2022 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27#pragma once
28
29#include <EASTL/functional.h>
30#include <stdint.h>
31
32#include <source_location>
33
34namespace psyqo {
35
36namespace DMA {
37
42
43}
44
45class Application;
46
56namespace Kernel {
57
58#ifdef PSYQO_RELEASE
59static constexpr bool debugMode = false;
60#else
61static constexpr bool debugMode = true;
62#endif
63
64namespace Internal {
65static inline uint32_t getCop0Status() {
66#ifndef PS1_PC_PORT
67 uint32_t r;
68 asm volatile("mfc0 %0, $12 ; nop" : "=r"(r));
69 return r;
70#else
71 return 0;
72#endif
73}
74
75static inline void setCop0Status(uint32_t r) {
76#ifndef PS1_PC_PORT
77 asm("mtc0 %0, $12 ; nop" : : "r"(r));
78#endif
79}
80
81[[noreturn]] void abort(const char* msg, std::source_location location = std::source_location::current());
82[[noreturn]] void abort();
83
84} // namespace Internal
85
92static inline void fastEnterCriticalSection() {
93#ifndef PS1_PC_PORT
94 asm volatile("mtc0 %0, $12 ; nop ; nop" : : "r"(0x40000000));
95#endif
96}
97
103static inline void fastLeaveCriticalSection() {
104#ifndef PS1_PC_PORT
105 asm volatile("mtc0 %0, $12" : : "r"(0x40000401));
106#endif
107}
108
109// Compiler barrier: memory accesses above it stay ahead of the CHCR store that starts a DMA.
110static inline void dmaReleaseBarrier() { __asm__ volatile("" ::: "memory"); }
111
112// Compiler barrier: memory accesses below it stay after the point a DMA was seen complete.
113static inline void dmaAcquireBarrier() { __asm__ volatile("" ::: "memory"); }
114
125template <typename T>
126static void waitForStatus(T mask, T expected, const volatile T* value) {
127 while ((*value & mask) != expected);
128 dmaAcquireBarrier();
129}
130
131enum class DMA : unsigned {
132 MDECin,
133 MDECout,
134 GPU,
135 CDRom,
136 SPU,
137 EXP1,
138 OTC,
139 Max,
140};
141
142enum class IRQ : unsigned {
143 VBlank,
144 GPU,
145 CDRom,
146 DMA,
147 Timer0,
148 Timer1,
149 Timer2,
151 SIO,
152 SPU,
153 PIO,
154 Max,
155};
156
160[[noreturn]] static inline void abort(const char* msg,
161 std::source_location location = std::source_location::current()) {
162 if constexpr (debugMode) {
163 Internal::abort(msg, location);
164 } else if constexpr (!debugMode) {
165 (void)msg;
166 (void)location;
168 }
169}
170
202void takeOverKernel();
203
207bool isKernelTakenOver();
208
226
244void queueIRQHandler(IRQ irq, eastl::function<void()>&& lambda);
245
255uint32_t openEvent(uint32_t classId, uint32_t spec, uint32_t mode, eastl::function<void()>&& lambda);
256
270unsigned registerDmaEvent(DMA channel, eastl::function<void()>&& lambda);
271
279
286void enableDma(DMA channel, unsigned priority = 7);
287
293void disableDma(DMA channel);
294
300void unregisterDmaEvent(unsigned slot);
301
312void queueCallback(eastl::function<void()>&& lambda);
313
323void queueCallbackFromISR(eastl::function<void()>&& lambda);
324
345void setBreakHandler(unsigned category, eastl::function<bool(uint32_t)>&& handler);
346
352void queuePsyqoBreakHandler(eastl::function<bool(uint32_t)>&& handler);
353
354namespace Internal {
355void pumpCallbacks();
356void prepare(Application&);
357void addInitializer(eastl::function<void(Application&)>&& lambda);
358void addOnFrame(eastl::function<void()>&& lambda);
359void beginFrame();
360[[noreturn]] void crashHandler(uint32_t exceptionCode, uint32_t* kernelRegisters);
361} // namespace Internal
362
366inline void assert(bool condition, const char* message,
367 std::source_location location = std::source_location::current()) {
368 if constexpr (debugMode) {
369 if (!condition) {
370 Internal::abort(message, location);
372 }
373 } else if constexpr (!debugMode) {
374 (void)message;
375 (void)location;
376 if (!condition) {
379 }
380 }
381}
382
383} // namespace Kernel
384
385} // namespace psyqo
int irq
Definition cdltest.c:296
The application class.
Definition application.hh:49
uint32_t r
Definition cpu.c:310
IRQ
Definition irq.h:31
__asm__(" .section .text.monitorSlotEntry, \"ax\", @progbits\n" " .align 2\n" " .global monitorSlotEntry\n" " .type monitorSlotEntry, @function\n" " .set push\n" " .set noreorder\n" " .set noat\n" "monitorSlotEntry:\n" " mfc0 $v0, $13\n" " nop\n" " andi $v0, $v0, 0x7c\n" " beqz $v0, 1f\n" " srl $v0, $v0, 2\n" " li $v1, " MON_STR(MON_SLOT_EXCMASK) "\n" " srlv $v1, $v1, $v0\n" " andi $v1, $v1, 1\n" " bnez $v1, 2f\n" " nop\n" " jr $ra\n" " nop\n" "1:\n" MON_SLOT_RX_TEST " jr $ra\n" " nop\n" "2:\n" " sw $a0, 0x10($k0)\n" " sw $a1, 0x14($k0)\n" " sw $a2, 0x18($k0)\n" " sw $a3, 0x1c($k0)\n" " mfc0 $a0, $12\n" " nop\n" " sw $a0, 0x8c($k0)\n" " mfc0 $a1, $13\n" " nop\n" " sw $a1, 0x90($k0)\n" " sw $k1, 0x6c($k0)\n" " sw $s0, 0x40($k0)\n" " sw $s1, 0x44($k0)\n" " sw $s2, 0x48($k0)\n" " sw $s3, 0x4c($k0)\n" " sw $s4, 0x50($k0)\n" " sw $s5, 0x54($k0)\n" " sw $s6, 0x58($k0)\n" " sw $s7, 0x5c($k0)\n" " sw $t0, 0x20($k0)\n" " sw $t1, 0x24($k0)\n" " sw $t2, 0x28($k0)\n" " sw $t3, 0x2c($k0)\n" " sw $t4, 0x30($k0)\n" " sw $t5, 0x34($k0)\n" " sw $t6, 0x38($k0)\n" " sw $t7, 0x3c($k0)\n" " sw $t8, 0x60($k0)\n" " sw $t9, 0x64($k0)\n" " sw $gp, 0x70($k0)\n" " sw $sp, 0x74($k0)\n" " sw $fp, 0x78($k0)\n" " mfhi $a0\n" " nop\n" " sw $a0, 0x84($k0)\n" " mflo $a0\n" " nop\n" " sw $a0, 0x88($k0)\n" " move $s0, $ra\n" " la $sp, monitorSlotStack + " MON_STR(MONITOR_SLOT_STACK_WORDS) " * 4 - 16\n" " jal monitorSlotDispatch\n" " nop\n" " lw $k0, 0x108($zero)\n" " move $ra, $s0\n" " lw $k0, 0($k0)\n" " nop\n" " addiu $k0, $k0, 8\n" " lw $a0, 0x84($k0)\n" " lw $a1, 0x88($k0)\n" " mthi $a0\n" " mtlo $a1\n" " lw $a0, 0x10($k0)\n" " lw $a1, 0x14($k0)\n" " lw $a2, 0x18($k0)\n" " lw $a3, 0x1c($k0)\n" " lw $t0, 0x20($k0)\n" " lw $t1, 0x24($k0)\n" " lw $t2, 0x28($k0)\n" " lw $t3, 0x2c($k0)\n" " lw $t4, 0x30($k0)\n" " lw $t5, 0x34($k0)\n" " lw $t6, 0x38($k0)\n" " lw $t7, 0x3c($k0)\n" " lw $t8, 0x60($k0)\n" " lw $t9, 0x64($k0)\n" " lw $s0, 0x40($k0)\n" " lw $sp, 0x74($k0)\n" " jr $ra\n" " nop\n" " .set pop\n" " .size monitorSlotEntry, . - monitorSlotEntry\n" " .previous\n")
DmaCallback
Definition kernel.hh:38
@ FROM_MAIN_LOOP
Definition kernel.hh:40
@ FROM_ISR
Definition kernel.hh:39
void pumpCallbacks()
Definition kernel.cpp:423
void prepare(Application &)
Definition kernel.cpp:347
void crashHandler(uint32_t exceptionCode, uint32_t *kernelRegisters)
Definition crash-handler.cpp:145
void addOnFrame(eastl::function< void()> &&lambda)
Definition kernel.cpp:449
void beginFrame()
Definition kernel.cpp:453
void addInitializer(eastl::function< void(Application &)> &&lambda)
Definition kernel.cpp:284
void abort()
Definition kernel.cpp:201
uint32_t openEvent(uint32_t classId, uint32_t spec, uint32_t mode, eastl::function< void()> &&lambda)
A C++ wrapper around the openEvent syscall.
Definition kernel.cpp:208
void queueCallbackFromISR(eastl::function< void()> &&lambda)
Queues a callback to be called from the main thead.
Definition kernel.cpp:417
void assert(bool condition, const char *message, std::source_location location=std::source_location::current())
A simple assert macro.
Definition kernel.hh:366
unsigned registerDmaEvent(DMA channel, eastl::function< void()> &&lambda)
Sets an ISR callback for a given DMA channel.
Definition kernel.cpp:217
DMA
Definition kernel.hh:131
void queuePsyqoBreakHandler(eastl::function< bool(uint32_t)> &&handler)
Queues a break handler for psyqo's reserved category.
Definition kernel.cpp:111
void disableDma(DMA channel)
Disables the given DMA channel.
Definition kernel.cpp:253
void installCrashHandler()
Installs a crash handler for the application.
Definition kernel.cpp:172
void setBreakHandler(unsigned category, eastl::function< bool(uint32_t)> &&handler)
Sets a break handler for a given category.
Definition kernel.cpp:105
void flushCache()
Flushes the i-cache.
IRQ
Definition kernel.hh:142
void queueCallback(eastl::function< void()> &&lambda)
Queues a callback to be called from the main thead.
Definition kernel.cpp:410
void unregisterDmaEvent(unsigned slot)
Frees the given DMA callback slot.
Definition kernel.cpp:266
bool isKernelTakenOver()
Returns whether the kernel has been taken over.
Definition kernel.cpp:115
void enableDma(DMA channel, unsigned priority=7)
Enables the given DMA channel.
Definition kernel.cpp:235
void queueIRQHandler(IRQ irq, eastl::function< void()> &&lambda)
Queues an IRQ handler to be called from the exception handler.
Definition kernel.cpp:184
void takeOverKernel()
Takes over the kernel. Can only be called once inside the main function.
Definition kernel.cpp:140
Definition lua.hh:40
static int value
Definition syscalls.h:553
__builtin_unreachable()
static uint32_t spec
Definition syscalls.h:393
static uint32_t uint32_t void(* handler)())
Definition syscalls.h:401
static void uint32_t mode
Definition syscalls.h:274