diff --git a/game/kernel/jak1/kmachine.cpp b/game/kernel/jak1/kmachine.cpp index 2f7e51fdb1..b9e292f79b 100644 --- a/game/kernel/jak1/kmachine.cpp +++ b/game/kernel/jak1/kmachine.cpp @@ -335,7 +335,6 @@ int InitMachine() { // MsgErr("dkernel: !init pad\n"); // } - // do this always if (MasterDebug) { // connect to GOAL compiler InitGoalProto(); } diff --git a/game/kernel/jak2/kmachine.cpp b/game/kernel/jak2/kmachine.cpp index 358f63b141..ab6f1c49c8 100644 --- a/game/kernel/jak2/kmachine.cpp +++ b/game/kernel/jak2/kmachine.cpp @@ -382,9 +382,9 @@ int InitMachine() { // if (scePadInit(0) != 1) { // MsgErr("dkernel: !init pad\n"); // } - // if (MasterDebug != 0) { - InitGoalProto(); - // } + if (MasterDebug) { + InitGoalProto(); + } printf("InitSound\n"); InitSound(); @@ -410,12 +410,11 @@ int InitMachine() { */ int ShutdownMachine() { Msg(6, "kernel: machine shutdown (reason %d)\n", MasterExit); - ASSERT(false); - /* + StopIOP(); ShutdownSound(); CloseListener(); - */ + ShutdownGoalProto(); // OpenGOAL only - kill ps2 VM diff --git a/game/kernel/jak2/kprint.cpp b/game/kernel/jak2/kprint.cpp index 1c442f8c19..1758fe065f 100644 --- a/game/kernel/jak2/kprint.cpp +++ b/game/kernel/jak2/kprint.cpp @@ -352,7 +352,7 @@ s32 format_impl_jak2(uint64_t* args) { case 'p': { *output_ptr = 0; s8 arg0 = argument_data[0].data[0]; - u32 in = arg_regs[arg_reg_idx++]; + u64 in = arg_regs[arg_reg_idx++]; if (arg0 == -1) { jak2::print_object(in); } else { @@ -373,7 +373,7 @@ s32 format_impl_jak2(uint64_t* args) { case 'i': { *output_ptr = 0; s8 arg0 = argument_data[0].data[0]; - u32 in = arg_regs[arg_reg_idx++]; + u64 in = arg_regs[arg_reg_idx++]; if (arg0 == -1) { inspect_object(in); } else { @@ -522,7 +522,17 @@ s32 format_impl_jak2(uint64_t* args) { output_ptr++; if (original_dest == s7.offset + FIX_SYM_TRUE) { - // do nothing, we're done + // #t means to put it in the print buffer + + // change for Jak 2: if we are disk-booting and do a (format #t, immediately flush to stdout. + // we'd get these eventually in ClearPending, but for some reason they flush these here. + // This is nicer because we may crash in between here and flushing the print buffer. + if (DiskBoot) { + printf("%s", PrintPendingLocal3); + fflush(stdout); + PrintPending = make_ptr(PrintPendingLocal2).cast(); + } + return 0; } else if (original_dest == s7.offset + FIX_SYM_FALSE) { // #f means print to new string diff --git a/game/kernel/jak2/kscheme.cpp b/game/kernel/jak2/kscheme.cpp index 83d5547e94..e51848e578 100644 --- a/game/kernel/jak2/kscheme.cpp +++ b/game/kernel/jak2/kscheme.cpp @@ -870,13 +870,77 @@ Ptr set_fixed_type(u32 offset, return symbol_value; } +static bool in_valid_memory_for_new_type(u32 addr) { + if (SymbolTable2.offset <= addr && addr < 0x8000000) { + return true; + } + + if (addr < 0x100000 && addr >= 0x84000) { + return true; + } + return false; +} + +static bool is_valid_type(u32 addr) { + if ((addr & 7) != 4) { + return false; + } + + if (*Ptr(addr - 4) != u32_in_fixed_sym(FIX_SYM_TYPE_TYPE)) { + return false; + } + + return true; +} /*! * New method of type. A GOAL (deftype) will end up calling this method. * Internally does an intern. */ u64 new_type(u32 symbol, u32 parent, u64 flags) { - ASSERT(false); // nyi - return 0; + u32 n_methods = (flags >> 32) & 0xffff; + if (n_methods == 0) { + // 12 methods used as default, if the user has not provided us with a number + n_methods = 12; + } + + // copy methods + u32 parent_num_methods = Ptr(parent)->num_methods; + auto new_type_obj = + Ptr(intern_type(sym_to_string(Ptr>(symbol)).offset, n_methods)); + u32 original_type_list_value = new_type_obj->memusage_method.offset; + Ptr* child_slots = &(new_type_obj->new_method); + Ptr* parent_slots = &(Ptr(parent)->new_method); + for (u32 i = 0; i < n_methods; i++) { + if (i < parent_num_methods) { // bug fix from jak 1 + child_slots[i] = parent_slots[i]; + } else { + child_slots[i].offset = 0; + } + } + + // deal with loading-level types + if (u32_in_fixed_sym(FIX_SYM_LOADING_LEVEL) == u32_in_fixed_sym(FIX_SYM_GLOBAL_HEAP)) { + // not loading a level + + // we'll consider a type list if it's #f or a valid type + if (original_type_list_value && (original_type_list_value == s7.offset || + (in_valid_memory_for_new_type(original_type_list_value) && + is_valid_type(original_type_list_value)))) { + printf("case 1 for new_type level types\n"); + new_type_obj->memusage_method.offset = original_type_list_value; + } + } else { + if (original_type_list_value == 0) { + // loading a level, but the type is global + MsgWarn("dkernel: loading-level init of type %s, but was interned global (this is okay)\n", + sym_to_string(new_type_obj->symbol)->data()); + } else { + printf("case 2 for new_type level types\n"); + new_type_obj->memusage_method.offset = original_type_list_value; + } + } + + return set_type_values(new_type_obj, Ptr(parent), flags).offset; } /*! @@ -897,8 +961,73 @@ u64 type_typep(Ptr t1, Ptr t2) { } u64 method_set(u32 type_, u32 method_id, u32 method) { - ASSERT(false); // nyi - return 0; + Ptr type(type_); + if (method_id > 127) + printf("[METHOD SET ERROR] tried to set method %d\n", method_id); + + auto existing_method = type->get_method(method_id).offset; + + if (method == 1) { + method = 0; + } else if (method == 0) { + return 0; + } else if (method == 2) { + method = type->parent->get_method(method_id).offset; + printf("[Method Set] got 2, inheriting\n"); + } + + // do the set + type->get_method(method_id).offset = method; + + // now, propagate to children + // we don't track children directly, so we end up having to iterate the whole symbol to find all + // types. This is slow, so we only do it in some cases + + // the condition is either setting *enable-method-set* in GOAL, or if we're debugging without the + // disk boot. The point of doing this in debug is just to print warning messages. + if (*EnableMethodSet || (!FastLink && MasterDebug && !DiskBoot)) { + auto sym = Ptr>>(s7.offset); + for (; sym.offset < LastSymbol.offset; sym.offset += 4) { + auto sym_value = sym->value(); + if (in_valid_memory_for_new_type(sym_value.offset) && (sym_value.offset & 7) == 4 && + *Ptr(sym_value.offset - 4) == u32_in_fixed_sym(FIX_SYM_TYPE_TYPE) && + method_id < sym_value->num_methods && + sym_value->get_method(method_id).offset == existing_method && + type_typep(sym_value, type) != s7.offset) { + if (FastLink != 0) { + printf("************ WARNING **************\n"); + printf("method %d of %s redefined - you must define class heirarchies in order now\n", + method_id, sym_to_string(sym)->data()); + printf("***********************************\n"); + } + // todo remove once checked + printf("doing method set: %s %d\n", sym_to_string(sym)->data(), method_id); + sym_value->get_method(method_id).offset = method; + } + } + + sym = Ptr>>(SymbolTable2.offset); + for (; sym.offset < s7.offset; sym.offset += 4) { + auto sym_value = sym->value(); + if (in_valid_memory_for_new_type(sym_value.offset) && (sym_value.offset & 7) == 4 && + *Ptr(sym_value.offset - 4) == u32_in_fixed_sym(FIX_SYM_TYPE_TYPE) && + method_id < sym_value->num_methods && + sym_value->get_method(method_id).offset == existing_method && + type_typep(sym_value, type) != s7.offset) { + if (FastLink != 0) { + printf("************ WARNING **************\n"); + printf("method %d of %s redefined - you must define class heirarchies in order now\n", + method_id, sym_to_string(sym)->data()); + printf("***********************************\n"); + } + // todo remove once checked + printf("doing method set: %s %d\n", sym_to_string(sym)->data(), method_id); + sym_value->get_method(method_id).offset = method; + } + } + } + + return method; } /*!