Difference between revisions of "Nintendo 64 - Nintendo Switch Online"
Line 44: | Line 44: | ||
The struct passed as the InBuffer to [[JIT_services#Control|Control]] is now 0xE00-bytes instead of 0xEB0-bytes. The internal workmem offsets / layout changed. Various funcs were updated etc. | The struct passed as the InBuffer to [[JIT_services#Control|Control]] is now 0xE00-bytes instead of 0xEB0-bytes. The internal workmem offsets / layout changed. Various funcs were updated etc. | ||
+ | |||
+ | The 0xE00-byte controldata struct has the following structure (all addrs/data are from the emulator user-process): | ||
+ | |||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Offset | ||
+ | ! Size | ||
+ | ! Description | ||
+ | |- | ||
+ | | 0x0 || 0x8 || Data addr: g_pGPR | ||
+ | |- | ||
+ | | 0x8 || 0x8 || Data addr: g_pFPR | ||
+ | |- | ||
+ | | 0x10 || 0x8 || Data addr: g_pCP0 | ||
+ | |- | ||
+ | | 0x18 || 0x8 || Data addr: g_nRegHi | ||
+ | |- | ||
+ | | 0x20 || 0x8 || Data addr: g_nRegLo | ||
+ | |- | ||
+ | | 0x28 || 0x8 || Data addr. | ||
+ | |- | ||
+ | | 0x30 || 0x8 || Data addr: g_nFCSR | ||
+ | |- | ||
+ | | 0x38 || 0x8 || Data addr: g_bN64CpuCmpEndCheck | ||
+ | |- | ||
+ | | 0x40 || 0x8 || Data addr: g_nN64CpuPC | ||
+ | |- | ||
+ | | 0x48 || 0x8 || Data addr: g_nN64CpuJmpPC. s32, normally -1. When not -1 this is a value which can be copied into g_nN64CpuJmpPC by the generated code, with g_nN64CpuJmpPC being reset to -1 afterwards regardless of the original value. | ||
+ | |- | ||
+ | | 0x50 || 0x8 || Data addr. | ||
+ | |- | ||
+ | | 0x58 || 0x8 || Data addr: g_nN64CpuHaveExp | ||
+ | |- | ||
+ | | 0x60 || 0x6A8 || Array of funcptrs. Called with w0=instruction_value from generated code for handling instructions' implementation, when the plugin itself doesn't handle it. | ||
+ | |- | ||
+ | | 0x708 || 0x8 || Funcptr: <code>n64CPUProcInstCOP1Check()</code> | ||
+ | |- | ||
+ | | 0x710 || 0x8 || Funcptr. | ||
+ | |- | ||
+ | | 0x718 || 0x8 || Funcptr. | ||
+ | |- | ||
+ | | 0x720 || 0x8 || Funcptr: <code>n64CPUSetRegisterCP0(int, unsigned int)</code> | ||
+ | |- | ||
+ | | 0x728 || 0x8 || Funcptr: <code>n64CPUGetRegisterCP0(int)</code> | ||
+ | |- | ||
+ | | 0x730 || 0x20 || Funcptrs for reading data: <code>n64MemDefaultRead{bitsize}(unsigned int)</code>, where bitsize is {8, 16, 32, 64} (32 uses <code>n64MemDefaultRead32WithDestLog</code>). Unused by the plugin. | ||
+ | |- | ||
+ | | 0x750 || 0x20 || Funcptrs for reading Special data: <code>n64MemDefaultReadSpecial{bitsize}(unsigned int)</code>, where bitsize is {8, 16, 32, 64}. | ||
+ | |- | ||
+ | | 0x770 || 0x20 || Funcptrs for writing data: <code>n64MemDefaultWrite{bitsize}(unsigned int, ...)</code>, where bitsize is {8, 16, 32, 64} (32 uses <code>n64MemDefaultWrite32WithDestLog</code>). Unused by the plugin. | ||
+ | |- | ||
+ | | 0x790 || 0x20 || Funcptrs for reading data via the WithDestLog version: <code>n64MemDefaultRead{bitsize}WithDestLog(unsigned int)</code>, where bitsize is {8, 16, 32, 64}. | ||
+ | |- | ||
+ | | 0x7B0 || 0x20 || Funcptrs for writing data via the WithDestLog version: <code>n64MemDefaultWrite{bitsize}WithDestLog(unsigned int, ...)</code>, where bitsize is {8, 16, 32, 64}. | ||
+ | |- | ||
+ | | 0x7D0 || 0x8 || Funcptr: <code>n64CPU_CallLuaAfterInst(unsigned int, unsigned int)</code> | ||
+ | |- | ||
+ | | 0x7D8 || 0x8 || Funcptr: <code>n64CPU_CallLuaBeforeInst(unsigned int, unsigned int)</code> | ||
+ | |- | ||
+ | | 0x7E0 || 0x8 || Funcptr. | ||
+ | |- | ||
+ | | 0x7E8 || 0x4 || Array count for the the following array. | ||
+ | |- | ||
+ | | 0x7EC || 0x180 (0x20*0xC) || Array data with the above count, each entry is 0xC-bytes. The emulator loads this from config array "Idle". +0 = u32 emu_pc_addr (config "JmpAddr"), +4 = u32 instruction_value (config "JmpInst"), +8 = u32 is_idle (config "IsIdle", 0x1 = enabled). | ||
+ | |- | ||
+ | | 0x96C || 0x4 || Array count for the the following array. | ||
+ | |- | ||
+ | | 0x970 || 0x280 (0x20*0x14) || Array data with the above count, each entry is 0x14-bytes. The emulator loads this from config array "SpecialInst". +0 = u32 emu_pc_addr (config "Addr"), +4 = u32 instruction_value (config "Inst"), +8 = u32 flags. The emulator sets the flags to 0 by default, then compares config "Type" with various strings to determine the value. Flags: bit0 = Type "BreakLoop", bit5 = Type "LoadFrameBuffer", bit6 = Type "Lua_BeforeInst", bit7 = Type "Lua_AfterInst". | ||
+ | |||
+ | When the config for {any of the previously mentioned Type strings} is set to value 1, the emulator will also enable the corresponding flags bit mentioned above. Likewise with config "Return", which sets flags bit8. | ||
+ | |||
+ | When the plugin loads a funcptr from +0x790, it will load a funcptr from +0x750 instead if there's a matching entry here which has bit5 set. | ||
+ | |- | ||
+ | | 0xBF0 || 0x4 || Array count for the the following array. The plugin doesn't use this. | ||
+ | |- | ||
+ | | 0xBF4 || 0x80 (0x10*0x8) || Array data with the above count, each entry is 0x8-bytes. The emulator loads this from config array "FrameBuffer". +0 = u32 (config "Addr"), +4 = u32 (config "Length"). The plugin doesn't use this. | ||
+ | |- | ||
+ | | 0xC74 || 0x4 || Array count for the the following array. | ||
+ | |- | ||
+ | | 0xC78 || 0x180 (0x20*0xC) || Array data with the above count, each entry is 0xC-bytes. | ||
+ | |- | ||
+ | | 0xDF8 || 0x4 || Set to 0 by default, then if available the emulator sets bit flags here depending on the content of the config for <code>"Cmp", "g_nN64CpuCmpTLBCheckLevel"</code>. | ||
+ | |- | ||
+ | | 0xDFC || 0x4 || Set to 0 by default by the emulator. With config <code>"Cmp", "CodeMultiAddr"</code> this is set to 1. Config <code>"Cmp", "BlockDynamicPC"</code> from [[Super_Mario_3D_All-Stars|SM3DAS]] is not supported. The plugin doesn't use this field, since support for "BlockDynamicPC" was removed. All code which used to use this now assumes val!=2, with code for ==2 being removed. | ||
+ | |} |
Revision as of 06:19, 6 November 2021
This page documents the N64 application available via Nintendo Switch Online.
The internal name is "Hovercraft".
This uses an updated version of the N64 emulator used by SM3DAS. Like SM3DAS, Vulkan is used for rendering.
This saves various PlayReports. This also uses bcat.
NPDM
Same as SM3DAS Mario64 (besides programId etc), except the following services are additionally accessible: audout:u, bcat:u, bsd:u, bsdcfg, friend:u, nifm:u, nsd:u, sfdnsres, ssl. Flags is 0x27.
Details
Like SM3DAS, this uses JIT for running the emulated executable. The game archives also contains an AOT NRO. A NRO does get loaded, however it's not used other than that (no symbols from the NRO are resolved). Patches are applied at runtime with the config/lua files from the game archives.
A maximum of 0x1000-bytes are loaded from the launch-parameter, with buf[read_size]=0. Hence, this is a string. When available, this seems to be used to select which game to launch.
RomFs contains the following:
- "/kc.dat", "/Pipeline.cache", "/shader_font_frag.spv", "/shader_p1_frag.spv", "/shader_p1_vert.spv", "/shader_p2_srgb_frag.spv", "/shader_vulkan_frag.spv", "/shader_vulkan_vert.spv".
- "/.nrr/" contains:
- "/bootapp/" contains "init.json", "resources.json", and "resources/" which contains:
- Various UI/graphics data is stored here under various sub-dirs. This also includes "scripts/", which contains Lua scripts in bytecode form.
- One of these scripts at "/scripts/constants_nuse.lua" in the raw data, contains among various other data: "FirstDeliveryDate" "2019-09-01".
- Various UI/graphics data is stored here under various sub-dirs. This also includes "scripts/", which contains Lua scripts in bytecode form.
- "/nro/" contains "libHovercraftJITPlugin.nro", the NRO for the JitPlugin.
- "/sysdata/shaders/mesh.spirv", "/sysdata/shaders/sprite.spirv"
- "/titles/" contains the data for the emulated games:
- "lclassics.titlesdb"
- There's a sub-dir for each game containing:
- "{dirname}-details.png"
- "{dirname}.bnz": ROM-image compressed directly with zlib.
- "{dirname}.dtz": cpio archive compressed directly with zlib, containing the following (these are under "metapack_temp\"):
- The data here has mostly the same structure/format as SM3DAS rom/{subdir}, without the unused NRR. Filenames have the same "{fileid}_{TitleCode}.ext" format. When any texture data is present, it's included directly in this directory.
- The .meta no longer contains "DataSection", which in SM3DAS specified what files to load from here.
- The .lua file is optional. Compared to SM3DAS, Mario64 here (regions E/P at least) no longer has a .lua file, and the only remaining patches in config are for "Idle" and "BreakLoop". There's also various config differences compared to SM3DAS.
- The data here has mostly the same structure/format as SM3DAS rom/{subdir}, without the unused NRR. Filenames have the same "{fileid}_{TitleCode}.ext" format. When any texture data is present, it's included directly in this directory.
- "{dirname}.png"
libHovercraftJITPlugin
This section documents the JIT plugin.
This is an updated version of the plugin used by SM3DAS. Besides compiler-version differences / funcs being moved around, there were actual code changes.
The struct passed as the InBuffer to Control is now 0xE00-bytes instead of 0xEB0-bytes. The internal workmem offsets / layout changed. Various funcs were updated etc.
The 0xE00-byte controldata struct has the following structure (all addrs/data are from the emulator user-process):
Offset | Size | Description |
---|---|---|
0x0 | 0x8 | Data addr: g_pGPR |
0x8 | 0x8 | Data addr: g_pFPR |
0x10 | 0x8 | Data addr: g_pCP0 |
0x18 | 0x8 | Data addr: g_nRegHi |
0x20 | 0x8 | Data addr: g_nRegLo |
0x28 | 0x8 | Data addr. |
0x30 | 0x8 | Data addr: g_nFCSR |
0x38 | 0x8 | Data addr: g_bN64CpuCmpEndCheck |
0x40 | 0x8 | Data addr: g_nN64CpuPC |
0x48 | 0x8 | Data addr: g_nN64CpuJmpPC. s32, normally -1. When not -1 this is a value which can be copied into g_nN64CpuJmpPC by the generated code, with g_nN64CpuJmpPC being reset to -1 afterwards regardless of the original value. |
0x50 | 0x8 | Data addr. |
0x58 | 0x8 | Data addr: g_nN64CpuHaveExp |
0x60 | 0x6A8 | Array of funcptrs. Called with w0=instruction_value from generated code for handling instructions' implementation, when the plugin itself doesn't handle it. |
0x708 | 0x8 | Funcptr: n64CPUProcInstCOP1Check()
|
0x710 | 0x8 | Funcptr. |
0x718 | 0x8 | Funcptr. |
0x720 | 0x8 | Funcptr: n64CPUSetRegisterCP0(int, unsigned int)
|
0x728 | 0x8 | Funcptr: n64CPUGetRegisterCP0(int)
|
0x730 | 0x20 | Funcptrs for reading data: n64MemDefaultRead{bitsize}(unsigned int) , where bitsize is {8, 16, 32, 64} (32 uses n64MemDefaultRead32WithDestLog ). Unused by the plugin.
|
0x750 | 0x20 | Funcptrs for reading Special data: n64MemDefaultReadSpecial{bitsize}(unsigned int) , where bitsize is {8, 16, 32, 64}.
|
0x770 | 0x20 | Funcptrs for writing data: n64MemDefaultWrite{bitsize}(unsigned int, ...) , where bitsize is {8, 16, 32, 64} (32 uses n64MemDefaultWrite32WithDestLog ). Unused by the plugin.
|
0x790 | 0x20 | Funcptrs for reading data via the WithDestLog version: n64MemDefaultRead{bitsize}WithDestLog(unsigned int) , where bitsize is {8, 16, 32, 64}.
|
0x7B0 | 0x20 | Funcptrs for writing data via the WithDestLog version: n64MemDefaultWrite{bitsize}WithDestLog(unsigned int, ...) , where bitsize is {8, 16, 32, 64}.
|
0x7D0 | 0x8 | Funcptr: n64CPU_CallLuaAfterInst(unsigned int, unsigned int)
|
0x7D8 | 0x8 | Funcptr: n64CPU_CallLuaBeforeInst(unsigned int, unsigned int)
|
0x7E0 | 0x8 | Funcptr. |
0x7E8 | 0x4 | Array count for the the following array. |
0x7EC | 0x180 (0x20*0xC) | Array data with the above count, each entry is 0xC-bytes. The emulator loads this from config array "Idle". +0 = u32 emu_pc_addr (config "JmpAddr"), +4 = u32 instruction_value (config "JmpInst"), +8 = u32 is_idle (config "IsIdle", 0x1 = enabled). |
0x96C | 0x4 | Array count for the the following array. |
0x970 | 0x280 (0x20*0x14) | Array data with the above count, each entry is 0x14-bytes. The emulator loads this from config array "SpecialInst". +0 = u32 emu_pc_addr (config "Addr"), +4 = u32 instruction_value (config "Inst"), +8 = u32 flags. The emulator sets the flags to 0 by default, then compares config "Type" with various strings to determine the value. Flags: bit0 = Type "BreakLoop", bit5 = Type "LoadFrameBuffer", bit6 = Type "Lua_BeforeInst", bit7 = Type "Lua_AfterInst".
When the config for {any of the previously mentioned Type strings} is set to value 1, the emulator will also enable the corresponding flags bit mentioned above. Likewise with config "Return", which sets flags bit8. When the plugin loads a funcptr from +0x790, it will load a funcptr from +0x750 instead if there's a matching entry here which has bit5 set. |
0xBF0 | 0x4 | Array count for the the following array. The plugin doesn't use this. |
0xBF4 | 0x80 (0x10*0x8) | Array data with the above count, each entry is 0x8-bytes. The emulator loads this from config array "FrameBuffer". +0 = u32 (config "Addr"), +4 = u32 (config "Length"). The plugin doesn't use this. |
0xC74 | 0x4 | Array count for the the following array. |
0xC78 | 0x180 (0x20*0xC) | Array data with the above count, each entry is 0xC-bytes. |
0xDF8 | 0x4 | Set to 0 by default, then if available the emulator sets bit flags here depending on the content of the config for "Cmp", "g_nN64CpuCmpTLBCheckLevel" .
|
0xDFC | 0x4 | Set to 0 by default by the emulator. With config "Cmp", "CodeMultiAddr" this is set to 1. Config "Cmp", "BlockDynamicPC" from SM3DAS is not supported. The plugin doesn't use this field, since support for "BlockDynamicPC" was removed. All code which used to use this now assumes val!=2, with code for ==2 being removed.
|