mirror of
				https://github.com/N64Recomp/N64ModernRuntime.git
				synced 2025-10-30 08:02:29 +00:00 
			
		
		
		
	Add modified o1Heap library and set up recomp heap (#66)
* Add modified o1Heap library and set up recomp heap * Fix missing include on POSIX systems
This commit is contained in:
		
							parent
							
								
									9e9ae173ee
								
							
						
					
					
						commit
						3e39c2ec34
					
				
					 8 changed files with 114 additions and 7 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							|  | @ -7,3 +7,6 @@ | |||
| [submodule "N64Recomp"] | ||||
| 	path = N64Recomp | ||||
| 	url = https://github.com/N64Recomp/N64Recomp | ||||
| [submodule "thirdparty/o1heap"] | ||||
| 	path = thirdparty/o1heap | ||||
| 	url = https://github.com/N64Recomp/o1heap | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ add_library(librecomp STATIC | |||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/euc-jp.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/files.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/flash.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/heap.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/math_routines.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/mods.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_events.cpp" | ||||
|  | @ -27,13 +28,16 @@ add_library(librecomp STATIC | |||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/sp.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/ultra_stubs.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/ultra_translation.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/vi.cpp") | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/vi.cpp" | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/o1heap/o1heap/o1heap.c" | ||||
| ) | ||||
| 
 | ||||
| target_include_directories(librecomp PUBLIC | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/include" | ||||
|     "${PROJECT_SOURCE_DIR}/../ultramodern/include" | ||||
|     "${PROJECT_SOURCE_DIR}/../thirdparty" | ||||
|     "${PROJECT_SOURCE_DIR}/../thirdparty/concurrentqueue" | ||||
|     "${PROJECT_SOURCE_DIR}/../thirdparty/o1heap" | ||||
| ) | ||||
| target_include_directories(librecomp PRIVATE | ||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/include/librecomp" | ||||
|  |  | |||
|  | @ -3,8 +3,11 @@ | |||
| 
 | ||||
| #include <cstdint> | ||||
| #include "ultramodern/ultra64.h" | ||||
| #include "librecomp/recomp.h" | ||||
| 
 | ||||
| namespace recomp { | ||||
|     // 2GB (Addressable upper half of rdram)
 | ||||
|     constexpr size_t mem_size = 2U * 1024U * 1024U * 1024U; | ||||
|     // We need a place in rdram to hold the PI handles, so pick an address in extended rdram
 | ||||
|     constexpr int32_t cart_handle = 0x80800000; | ||||
|     constexpr int32_t drive_handle = (int32_t)(cart_handle + sizeof(OSPiHandle)); | ||||
|  | @ -20,6 +23,14 @@ namespace recomp { | |||
|     constexpr uint32_t sram_base = 0x08000000; | ||||
|     constexpr uint32_t rom_base = 0x10000000; | ||||
|     constexpr uint32_t drive_base = 0x06000000; | ||||
| 
 | ||||
|     void register_heap_exports(); | ||||
|     void init_heap(uint8_t* rdram, uint32_t address); | ||||
|     void* alloc(uint8_t* rdram, size_t size); | ||||
|     void free(uint8_t* rdram, void* mem); | ||||
| } | ||||
| 
 | ||||
| extern "C" void recomp_alloc(uint8_t* rdram, recomp_context* ctx); | ||||
| extern "C" void recomp_free(uint8_t* rdram, recomp_context* ctx); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ namespace recomp { | |||
|         void register_overlays(const overlay_section_table_data_t& sections, const overlays_by_index_t& overlays); | ||||
| 
 | ||||
|         void register_patches(const char* patch_data, size_t patch_size, SectionTableEntry* code_sections, size_t num_sections); | ||||
|         void register_base_export(const std::string& name, recomp_func_t* func); | ||||
|         void register_base_exports(const FunctionExport* exports); | ||||
|         void register_base_events(char const* const* event_names); | ||||
|         void read_patch_data(uint8_t* rdram, gpr patch_data_address); | ||||
|  |  | |||
							
								
								
									
										45
									
								
								librecomp/src/heap.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								librecomp/src/heap.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| #include "o1heap/o1heap.h" | ||||
| 
 | ||||
| #include "librecomp/addresses.hpp" | ||||
| #include "librecomp/overlays.hpp" | ||||
| 
 | ||||
| static uint32_t heap_offset; | ||||
| 
 | ||||
| static inline O1HeapInstance* get_heap(uint8_t* rdram) { | ||||
|     return reinterpret_cast<O1HeapInstance*>(&rdram[heap_offset]); | ||||
| } | ||||
| 
 | ||||
| extern "C" void recomp_alloc(uint8_t* rdram, recomp_context* ctx) { | ||||
|     uint32_t offset = reinterpret_cast<uint8_t*>(recomp::alloc(rdram, ctx->r4)) - rdram; | ||||
|     ctx->r2 = offset + 0xFFFFFFFF80000000ULL; | ||||
| } | ||||
| 
 | ||||
| extern "C" void recomp_free(uint8_t* rdram, recomp_context* ctx) { | ||||
|     recomp::free(rdram, TO_PTR(void, ctx->r4)); | ||||
| } | ||||
| 
 | ||||
| void recomp::register_heap_exports() { | ||||
|     recomp::overlays::register_base_export("recomp_alloc", recomp_alloc); | ||||
|     recomp::overlays::register_base_export("recomp_free", recomp_free); | ||||
| } | ||||
| 
 | ||||
| void recomp::init_heap(uint8_t* rdram, uint32_t address) { | ||||
|     // Align the heap start to 16 bytes.
 | ||||
|     address = (address + 15U) & ~15U; | ||||
| 
 | ||||
|     // Calculate the offset of the heap from the start of rdram and the size of the heap.
 | ||||
|     heap_offset = address - 0x80000000U; | ||||
|     size_t heap_size = recomp::mem_size - heap_offset; | ||||
| 
 | ||||
|     printf("Initializing recomp heap at offset 0x%08X with size 0x%08X\n", heap_offset, static_cast<uint32_t>(heap_size)); | ||||
| 
 | ||||
|     o1heapInit(&rdram[heap_offset], heap_size); | ||||
| } | ||||
| 
 | ||||
| void* recomp::alloc(uint8_t* rdram, size_t size) { | ||||
|     return o1heapAllocate(get_heap(rdram), size); | ||||
| } | ||||
| 
 | ||||
| void recomp::free(uint8_t* rdram, void* mem) { | ||||
|     o1heapFree(get_heap(rdram), mem); | ||||
| } | ||||
|  | @ -55,6 +55,10 @@ void recomp::overlays::register_patches(const char* patch, std::size_t size, Sec | |||
|     std::memcpy(patch_data.data(), patch, size); | ||||
| } | ||||
| 
 | ||||
| void recomp::overlays::register_base_export(const std::string& name, recomp_func_t* func) { | ||||
|     base_exports.emplace(name, func); | ||||
| } | ||||
| 
 | ||||
| void recomp::overlays::register_base_exports(const FunctionExport* export_list) { | ||||
|     std::unordered_map<uint32_t, recomp_func_t*> patch_func_vram_map{}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,13 @@ | |||
| #include "librecomp/addresses.hpp" | ||||
| #include "librecomp/mods.hpp" | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #    define WIN32_LEAN_AND_MEAN | ||||
| #    include <Windows.h> | ||||
| #else | ||||
| #    include <sys/mman.h> | ||||
| #endif | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
| #define PATHFMT "%ls" | ||||
| #else | ||||
|  | @ -514,8 +521,8 @@ bool wait_for_game_started(uint8_t* rdram, recomp_context* context) { | |||
| 
 | ||||
|                 init(rdram, context, game_entry.entrypoint_address); | ||||
| 
 | ||||
|                 uint32_t mod_ram_used = 0; | ||||
|                 if (!game_entry.mod_game_id.empty()) { | ||||
|                     uint32_t mod_ram_used = 0; | ||||
|                     std::vector<recomp::mods::ModLoadErrorDetails> mod_load_errors; | ||||
|                     { | ||||
|                         std::lock_guard lock { mod_context_mutex }; | ||||
|  | @ -537,7 +544,9 @@ bool wait_for_game_started(uint8_t* rdram, recomp_context* context) { | |||
|                         return false; | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
| 
 | ||||
|                 recomp::init_heap(rdram, recomp::mod_rdram_start + mod_ram_used); | ||||
| 
 | ||||
|                 ultramodern::init_saving(rdram); | ||||
|                 ultramodern::load_shader_cache(game_entry.cache_data); | ||||
| 
 | ||||
|  | @ -599,9 +608,24 @@ void recomp::start( | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Allocate rdram_buffer
 | ||||
|     std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(rdram_size); | ||||
|     std::memset(rdram_buffer.get(), 0, rdram_size); | ||||
|     // Allocate rdram without comitting it. Use a platform-specific virtual allocation function
 | ||||
|     // that initializes to zero.
 | ||||
|     uint8_t* rdram; | ||||
|     bool alloc_failed; | ||||
| #ifdef _WIN32 | ||||
|     rdram = reinterpret_cast<uint8_t*>(VirtualAlloc(nullptr, mem_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); | ||||
|     alloc_failed = (rdram == nullptr); | ||||
| #else | ||||
|     rdram = (uint8_t*)mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | ||||
|     alloc_failed = rdram == reinterpret_cast<uint8_t*>(MAP_FAILED); | ||||
| #endif | ||||
| 
 | ||||
|     if (alloc_failed) { | ||||
|         ultramodern::error_handling::message_box("Failed to allocate memory!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     recomp::register_heap_exports(); | ||||
| 
 | ||||
|     std::thread game_thread{[](ultramodern::renderer::WindowHandle window_handle, uint8_t* rdram) { | ||||
|         debug_printf("[Recomp] Starting\n"); | ||||
|  | @ -614,7 +638,7 @@ void recomp::start( | |||
| 
 | ||||
|         // Loop until the game starts.
 | ||||
|         while (!wait_for_game_started(rdram, &context)) {} | ||||
|     }, window_handle, rdram_buffer.get()}; | ||||
|     }, window_handle, rdram}; | ||||
| 
 | ||||
|     while (!exited) { | ||||
|         ultramodern::sleep_milliseconds(1); | ||||
|  | @ -627,4 +651,18 @@ void recomp::start( | |||
|     ultramodern::join_event_threads(); | ||||
|     ultramodern::join_thread_cleaner_thread(); | ||||
|     ultramodern::join_saving_thread(); | ||||
|      | ||||
|     // Free rdram.
 | ||||
|     bool free_failed; | ||||
| #ifdef _WIN32 | ||||
|     // VirtualFree returns zero on failure.
 | ||||
|     free_failed = (VirtualFree(rdram, 0, MEM_RELEASE) == 0); | ||||
| #else | ||||
|     // munmap returns -1 on failure.
 | ||||
|     free_failed = (munmap(rdram, mem_size) == -1); | ||||
| #endif | ||||
| 
 | ||||
|     if (free_failed) { | ||||
|         printf("Failed to free rdram\n"); | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										1
									
								
								thirdparty/o1heap
									
										
									
									
										vendored
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								thirdparty/o1heap
									
										
									
									
										vendored
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | |||
| Subproject commit a124b850791db2a33f7354d2b0aa7da821cef6f5 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Wiseguy
						Wiseguy