jak-project/game/kernel/common/kscheme.cpp
water111 e630b50690
[ckernel] split by game version (#1559)
* temp

* split up kprint, other than format

* start kmachine

* split kmachine

* split kscheme

* split klink

* split klisten

* split remaining

* jak2 ckernel gets to nokernel loop
2022-06-26 18:17:11 -04:00

289 lines
7.4 KiB
C++

#include "kscheme.h"
#include "game/kernel/common/fileio.h"
#include "game/kernel/common/kmalloc.h"
#include "game/kernel/common/kprint.h"
// total number of symbols in the table
s32 NumSymbols;
// value of the GOAL s7 register, pointing to the middle of the symbol table
Ptr<u32> s7;
// used for crc32 calculation
u32 crc_table[0x100];
// pointer to the "second" symbol table
Ptr<u32> SymbolTable2;
// pointer to the last symbol
Ptr<u32> LastSymbol;
//! Controls link mode when EnableMethodSet = 0, MasterDebug = 1, DiskBoot = 0. Will enable a
//! warning message if EnableMethodSet = 1
u32 FastLink;
// set to true to enable propagating method overrides to child types
// this is an O(N_max_symbols) operation, so it is avoided when loading DGOs for levels.
// but is enabled when loading the engine.
Ptr<u32> EnableMethodSet;
void kscheme_init_globals_common() {
SymbolTable2.offset = 0;
LastSymbol.offset = 0;
NumSymbols = 0;
s7.offset = 0;
for (auto& x : crc_table) {
x = 0;
}
EnableMethodSet.offset = 0;
FastLink = 0;
}
/*!
* Initialize CRC Table.
*/
void init_crc() {
for (u32 i = 0; i < 0x100; i++) {
u32 n = i << 24;
for (u32 j = 0; j < 8; j++) {
n = n & 0x80000000 ? (n << 1) ^ CRC_POLY : (n << 1);
}
crc_table[i] = n;
}
}
/*!
* Take the CRC32 hash of some data
*/
u32 crc32(const u8* data, s32 size) {
uint32_t crc = 0;
for (int i = size; i != 0; i--, data++) {
crc = crc_table[crc >> 24] ^ ((crc << 8) | *data);
}
ASSERT(~crc);
return ~crc;
}
/*!
* Delete method for types which cannot have "delete" used on them.
* Prints an error to stdout and returns false.
*/
u64 delete_illegal(u32 obj) {
MsgErr("dkernel: illegal attempt to call delete method of static object @ #x%x\n", obj);
return s7.offset; // todo, maybe don't return anything?
}
/*!
* Wrapper around kmalloc to allow GOAL programs to allocate on kernel heaps.
*/
u64 goal_malloc(u32 heap, u32 size, u32 flags, u32 name) {
return kmalloc(Ptr<kheapinfo>(heap), size, flags, Ptr<String>(name)->data()).offset;
}
extern "C" {
// defined in asm_funcs.asm
#ifdef __linux__
uint64_t _call_goal_asm_linux(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, void* offset);
uint64_t _call_goal_on_stack_asm_linux(u64 rsp,
u64 u0,
u64 u1,
void* fptr,
void* st_ptr,
void* offset);
#elif _WIN32
uint64_t _call_goal_asm_win32(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, void* offset);
uint64_t _call_goal_on_stack_asm_win32(u64 rsp, void* fptr, void* st_ptr, void* offset);
#endif
}
/*!
* Wrapper around _call_goal_asm for calling a GOAL function from C.
* Calls from the parent stack.
*/
u64 call_goal(Ptr<Function> f, u64 a, u64 b, u64 c, u64 st, void* offset) {
// auto st_ptr = (void*)((uint8_t*)(offset) + st); updated for the new compiler!
void* st_ptr = (void*)st;
void* fptr = f.c();
#ifdef __linux__
return _call_goal_asm_linux(a, b, c, fptr, st_ptr, offset);
#elif _WIN32
return _call_goal_asm_win32(a, b, c, fptr, st_ptr, offset);
#endif
}
/*!
* Wrapper around _call_goal_asm_on_stack for switching stacks and calling a GOAL function there.
*/
u64 call_goal_on_stack(Ptr<Function> f, u64 rsp, u64 st, void* offset) {
void* st_ptr = (void*)st;
void* fptr = f.c();
#ifdef __linux__
return _call_goal_on_stack_asm_linux(rsp, 0, 0, fptr, st_ptr, offset);
#elif _WIN32
return _call_goal_on_stack_asm_win32(rsp, fptr, st_ptr, offset);
#endif
}
/*!
* Call a GOAL function with no arguments.
*/
u64 call_goal_function(Ptr<Function> func) {
return call_goal(func, 0, 0, 0, s7.offset, g_ee_main_mem);
}
/*!
* Default print method for structures.
* Structures have no runtime type info, so there's not much we can do here.
*/
u64 print_structure(u32 s) {
cprintf("#<structure @ #x%x>", s);
return s;
}
/*!
* Print an integer. Works correctly for 64-bit integers.
*/
u64 print_integer(u64 obj) {
// not sure why this is any better than cprintf("%ld") or similar. Maybe a tiny bit faster?
char* str = PrintPending.cast<char>().c();
if (!str) {
str = (PrintBufArea + 0x18).cast<char>().c();
}
PrintPending = make_ptr(strend(str)).cast<u8>();
kitoa((char*)PrintPending.c(), obj, 10, 0xffffffff, '0', 0);
return obj;
}
/*!
* Print a boxed integer. Works correctly for 64-bit integers. Assumes signed.
*/
u64 print_binteger(u64 obj) {
char* str = PrintPending.cast<char>().c();
if (!PrintPending.offset) {
str = (PrintBufArea + 0x18).cast<char>().c();
}
PrintPending = make_ptr(strend(str)).cast<u8>();
kitoa((char*)PrintPending.c(), ((s64)obj) >> 3, 10, 0xffffffff, '0', 0);
return obj;
}
/*!
* Print floating point number.
*/
u64 print_float(u32 f) {
// again not sure why this is any better than cprintf("%f") or similar. Maybe a tiny bit faster?
float ff;
*(u32*)&ff = f;
char* str = PrintPending.cast<char>().c();
if (!PrintPending.offset) {
str = (PrintBufArea + 0x18).cast<char>().c();
}
PrintPending = make_ptr(strend(str)).cast<u8>();
ftoa((char*)PrintPending.c(), ff, 0xffffffff, ' ', 4, 0);
return f;
}
/*!
* Print method for VU functions. Again, just prints address.
*/
u64 print_vu_function(u32 obj) {
cprintf("#<compiled vu-function @ #x%x>", obj);
return obj;
}
/*!
* Copy method that does no copying.
*/
u64 copy_fixed(u32 it) {
return it;
}
/*!
* Default copy for a structure. Since this has no idea of the actual type, it doesn't know what
* size to copy. So we do no copy and return a reference to the original data.
*/
u64 copy_structure(u32 it, u32 unknown) {
(void)unknown;
return it;
}
/*!
* Inspect an integer (works correctly on 64-bit integers)
*/
u64 inspect_integer(u64 obj) {
// and now we're using cprintf. Why doesn't print do this?
cprintf("[%16lx] fixnum %ld\n", obj, obj);
return obj;
}
/*!
* Inspect a boxed integer (works correctly on 64-integers)
*/
u64 inspect_binteger(u64 obj) {
cprintf("[%16lx] boxed-fixnum %ld\n", obj, s64(obj) >> 3);
return obj;
}
/*!
* Inspect a floating point number
*/
u64 inspect_float(u32 f) {
float ff;
ff = *(float*)(&f);
cprintf("[%8x] float ", f);
// likely copy-pasta - no need for this check because of the cprintf immediately before.
char* str = PrintPending.cast<char>().c();
if (!str) {
str = (PrintBufArea + 0x18).cast<char>().c();
}
PrintPending = make_ptr(strend(str)).cast<u8>();
ftoa(PrintPending.cast<char>().c(), ff, -1, ' ', 4, 0);
cprintf("\n");
return f;
}
/*!
* Inspect a structure.
*/
u64 inspect_structure(u32 obj) {
cprintf("[%8x] structure\n", obj);
return obj;
}
/*!
* Inspect a VU Function. Doesn't seem to be used. Also the concept of "vu-function"
* isn't really used. VU0 macro mode stuff goes in normal functions, and micro-mode stuff goes
* in a giant dump of many functions thats loaded and unloaded all at the same time.
*/
u64 inspect_vu_function(u32 obj) {
struct VuFunction {
u32 length;
u32 origin;
u32 qlength;
};
auto vf = Ptr<VuFunction>(obj);
cprintf("[%8x] vu-function\n\tlength: %d\n\torigin: #x%x\n\tqlength: %d\n", obj, vf->length,
vf->origin, vf->qlength);
return obj;
}
/*!
* This doesn't exist in the game, but we add it as a wrapper around kheapstatus.
* Note that this isn't a great inspect as it prints to stdout instead of the printbuffer.
*/
u64 inspect_kheap(u32 obj) {
kheapstatus(Ptr<kheapinfo>(obj));
return obj;
}