Skip to content

Full 64-bit migration#48

Open
birabittoh wants to merge 33 commits into
flyngmt:masterfrom
birabittoh:master
Open

Full 64-bit migration#48
birabittoh wants to merge 33 commits into
flyngmt:masterfrom
birabittoh:master

Conversation

@birabittoh

@birabittoh birabittoh commented Mar 25, 2026

Copy link
Copy Markdown

Update codebase to make the game work on many different platforms.

https://nightly.link/birabittoh/ACGC-PC-Port/workflows/build.yaml/master?preview

Tested working platforms as of commit be97585:

  • Linux i686
  • Linux x86_64
  • Windows i686
  • Windows x86_64
  • macOS ARM64
  • macOS x86_64

Known issues:

  • FIXED: both macOS versions can't load custom textures thank you @JPikachu
  • FIXED: all 64-bit builds instantly crash as soon as a gyroid starts playing audio
  • some minor line artifacts appear when closing the billboard keyboard and ui. Looks similar to the issue that was fixed in 396b6ca

@birabittoh birabittoh force-pushed the master branch 3 times, most recently from a85a704 to 3fbdf38 Compare March 25, 2026 09:26
@Project516

Copy link
Copy Markdown

@birabittoh is this similar to #33? seems to have identical commits, until the last few

@birabittoh

birabittoh commented Mar 26, 2026

Copy link
Copy Markdown
Author

@birabittoh is this similar to #33? seems to have identical commits, until the last few

It is! I created this draft because the original author explicitly said he wasn't going to spend any more time on it. I will actually open it once I get the game working on linux i686 and people confirm the macOS versions are still working.

@birabittoh

Copy link
Copy Markdown
Author

Finally fixed linux i686, now we just need confirmation for macOS.

@rcnsxpr7qm-gif

Copy link
Copy Markdown

I was able to get the arm version for macOS to run. I'm unable to get custom textures to work, though.

@birabittoh

Copy link
Copy Markdown
Author

I was able to get the arm version for macOS to run. I'm unable to get custom textures to work, though.

Interesting. Your file structure should look like this:

  • AnimalCrossing
  • texture_pack
    • GAF
      • Carpet
      • Clothing
      • ...

Can you run the game with the --verbose option and see if there are any errors?

@birabittoh birabittoh mentioned this pull request Mar 26, 2026
@rcnsxpr7qm-gif

Copy link
Copy Markdown

I was able to get the arm version for macOS to run. I'm unable to get custom textures to work, though.

Interesting. Your file structure should look like this:

  • AnimalCrossing
  • texture_pack
    • GAF
      • Carpet
      • Clothing
      • ...

Can you run the game with the --verbose option and see if there are any errors?

Yep, I got the texture pack installed correctly. I ran with verbose mode and got a handful of errors. I saved the log to a txt file.
AnimalCrossingLog.txt

@birabittoh

Copy link
Copy Markdown
Author

@rcnsxpr7qm-gif can you try this build and tell me if it's fixed?

@rcnsxpr7qm-gif

Copy link
Copy Markdown

@rcnsxpr7qm-gif can you try this build and tell me if it's fixed?

Still doesn't load the custom textures. It doesn't crash. Neither version has. It just defaults to the default textures.

I saved the log from the new version:
AnimalCrossingLog0328.txt

@rcnsxpr7qm-gif

rcnsxpr7qm-gif commented Mar 30, 2026

Copy link
Copy Markdown

I tested the macOS x86_64 version out on my old 2016 MBP running OS 12.7.6. It runs but the custom textures also refuse to load.

@birabittoh

Copy link
Copy Markdown
Author

@rcnsxpr7qm-gif can you please test this version when you have a minute? Thank you so much!

@rcnsxpr7qm-gif

Copy link
Copy Markdown

@rcnsxpr7qm-gif can you please test this version when you have a minute? Thank you so much!

Tested on both computers and they still fail to load the custom textures. I dunno if it's at all helpful, but I saved the logs from both versions.

AnimalCrossingLog0403ARM.txt
AnimalCrossingLog0403x86_64.txt

@JPikachu

Copy link
Copy Markdown

@birabittoh birabittoh#16
Hi, JPikachu here, Eden dev.
I fixed the custom textures and submitted it as a PR to you.

Here it is:
image

Let me know if I can help with anything else.

@birabittoh birabittoh marked this pull request as ready for review April 13, 2026 12:22
@JPikachu

Copy link
Copy Markdown

Can't wait for this to be merged now! ❤️

@JPikachu

Copy link
Copy Markdown

@birabittoh Could you send an image of what the artifacts look like on the ui please?

@birabittoh

birabittoh commented Apr 15, 2026

Copy link
Copy Markdown
Author

@birabittoh Could you send an image of what the artifacts look like on the ui please?

untitled.mp4
s1 s2

@JPikachu

  1. closing the input UI
  2. opening the keyboard

the exact same vertical lines used to appear while opening/closing the map screen, it was happening because of negative coordinates and I fixed it here

@JPikachu

Copy link
Copy Markdown

interesting, I'll see what I can do later. thank you

@Vmarcelo49

Copy link
Copy Markdown

@JPikachu @birabittoh any news on this pr?

Port the 32-bit x86 PC build to 64-bit platforms. The game compiles, links,
and boots to the trademark screen on macOS Apple Silicon with GCC 15.

Type system:
- u32/s32/u64/s64 use stdint.h fixed-width types on PC (always 4/8 bytes)
- Compile-time static_assert validation for type sizes

Pointer safety (~120 casts across 83 files):
- PC port layer: GXTexObj rewritten as proper struct, texture/EFB cache
  uses uintptr_t, ARAM DMA uses uintptr_t for MRAM addresses
- Decomp code: JKRExpHeap, JKRHeap, JKRAram, JKRThread, JKRMemArchive,
  JKRCompArchive, JKRDvdRipper, and 8 JUtility files wrapped in
  #ifdef TARGET_PC using uintptr_t (preserves decomp matching in #else)
- emu64: segments[], DL_stack[] are uintptr_t; resolved_imgaddr field
  avoids 32-bit bitfield truncation for texture addresses
- jaudio_NES: OFS2RAM/BANK_ENTRY macros, PTconvert relocation, Nas_HeapInit
  alignment, audio command buffer (Acmd.w1), RSP simulator pointer recovery
- Header fixes: ARStartDMA, ARQPostRequest, AIInitDMA declarations match
  uintptr_t implementations; OSRoundUp32B/OSRoundDown32B use uintptr_t

seg2k0 64-bit:
- Simple threshold check (addresses > 0x0FFFFFFF are real PC pointers)
- Pointer recovery from truncated 32-bit GBI values using image/arena base
- Eliminates VirtualQuery dependency on 64-bit

Build system:
- Removed 32-bit enforcement; added macOS platform support
- GCC required on 64-bit (Clang rejects pointer truncation in GBI statics)
- macOS: GL_SILENCE_DEPRECATION, forward-compatible GL context, Cocoa/IOKit
  frameworks, dladdr-based image detection, no elf.h dependency
- Clang-incompatible flags guarded; decomp -Wno-return-type for Clang

Runtime fixes:
- operator new/delete uses malloc/free (prevents macOS framework corruption);
  operator delete checks arena range for JKR heap pointers
- Audio heap doubled (0x70000→0xE0000) for wider 64-bit structs
- Arena increased to 48MB on 64-bit; system heap overhead adjusted
- malloc.h→stdlib.h on macOS; errno field conflict; bcmp/bcopy builtins;
  CARD sub-header long/s32 conflicts; _mem.h memcpy builtin conflicts

Known limitations:
- Static GBI display lists with direct C pointers use 0 placeholder
  (_GBI_STATIC_PTR), recovered at runtime via seg2k0 pointer recovery
- Audio bank struct layout mismatch (PTconvert reads void* from 32-bit
  ROM fields) causes crash during bank loading after trademark screen
- Requires GCC (brew install gcc) on macOS; Clang 64-bit not supported
Fix crashes on macOS ARM64 / Linux x86_64 caused by 64-bit pointer
truncation throughout the codebase. The game now boots crash-free
through trademark init and into the main game loop.

Audio system (system.c):
- Define GC-compat structs (smzwavetable_gc, wtstr_gc, perctable_gc,
  voicetable_gc, percvoicetable_gc) that match the GC binary layout
  with u32 for pointer fields
- Add Nas_BankOfsToAddr_Inner_PC + __WaveTouch_PC to allocate native
  64-bit structs from GC ROM data during bank ctrl relocation
- Add safety guards: __Link_BankNum NULL check,
  __Nas_SzCacheCheck_Inner default case, __Load_Bank_BG range check

Pointer truncation (22 files):
- GRAPH_ALLOC macro: (int) -> (intptr_t) for pointer arithmetic
- TwoHeadArena: (u32) -> (uintptr_t) in allocator functions
- __osMalloc: (u32) -> (uintptr_t) in macros and pointer math
- ARQRequest struct: u32 source/dest -> uintptr_t on 64-bit
- ALIGN_NEXT((u32)ptr) -> (uintptr_t) across 12+ game files
- m_play.c / famicom_emu.c: THA_alloc u32 -> uintptr_t

GBI display list (emu64.c):
- Recover full 64-bit pointer via pc_gbi_recover_ptr when setting
  segment bases in dl_G_MOVEWORD

Build config:
- Add BUGFIXES define to fix original game buffer overflows that
  crash on modern platforms with fortified libc
On 64-bit, Gwords.w1 is now uintptr_t (8 bytes) instead of u32,
making sizeof(Gfx) = 16. This allows static display list initializers
to store full 64-bit pointers via _GBI_STATIC_PTR(s) = (uintptr_t)(s)
instead of the 0u placeholder that produced a black screen.

gbi.h:
- Gwords.w1: u32 -> uintptr_t on 64-bit
- _GBI_STATIC_PTR: 0u -> (uintptr_t)(s) on 64-bit
- _GBI_SET_W1 / _GBI_SET_W1_RAW: new macros for runtime w1 writes
- All g* runtime macros updated to use _GBI_SET_W1

emu64.c:
- EMU64_GFX_COMPACT_PTR: builds packed 8-byte {w0,(u32)w1} buffer
  for safe casting to union member structs (Gsettile, Gsetcolor, etc.)
  whose second u32 field would land in padding with 16-byte Gfx
- All command handlers read pointers from gfx.words.w1 (full width)
  instead of union views that truncate to u32
- seg2k0 already returns full 64-bit values directly (> 0xFFFFFFFF)

emu64.hpp: rdpHalf_1 widened to uintptr_t, segchk param widened

Result: ~1300 GBI commands/frame, 70-95 triangles, 60-98 GL draws.
Game renders title screen and character movement is visible.
SDIFileEntry had void* mData at offset 0x10, making sizeof() = 0x18
on 64-bit instead of the RARC binary layout's 0x14. This caused
fileEntry++ iteration to misalign, breaking archive file lookups
(most resources returned address 0 from JW_GetAramAddress).

Fix: replace void* mData with u32 mData_pad on TARGET_PC to keep
the binary-compatible 0x14 stride. Store actual mData pointers in a
parallel heap-allocated array (mFileEntryDataPtrs) accessed via
getFileEntryData()/setFileEntryData() methods.

Updated: JKRAramArchive, JKRDvdArchive, JKRMemArchive,
JKRCompArchive, JKRArchivePri, JKRArchivePub (all mData accesses).

pallet_boy.bin now resolves to valid ARAM address (0x8a4080).
Texture/color rendering still WIP — ARAM DMA reads return zeros,
suggesting the resource data within the archive wasn't decompressed
or the ARAM buffer contents at those offsets are empty.
Updated the DVDFileInfo and DVDCommandBlock structures to ensure correct field offsets on 64-bit systems. This includes replacing hardcoded offsets with offsetof() macros for better maintainability and accuracy. Adjusted memory initialization to use sizeof() for the structures instead of fixed sizes, enhancing compatibility across different architectures. Additionally, added a new fast-forward feature in the main PC application loop and included pixel color diagnostics for debugging purposes.
- game.c: use %p format for crash diagnostic pointer printing
- m_card.c: cast pointer arithmetic through uintptr_t instead of u32
- m_mail.c: fix mMl_strlen to use typed pointer instead of u32 cast
- m_font_main.c_inc: fix vertex alpha (255), cache char code to avoid
  re-dereferencing, clean up trailing whitespace
- emu64.c: fix G_TEXTURE dirty check to compare against incoming
  texture command rather than self
chasem-dev and others added 21 commits June 1, 2026 10:24
Static display lists used hardcoded byte offsets (e.g. anime_4_txt + 0x18)
to index into Gfx arrays via segment addresses. These offsets assumed
sizeof(Gfx) == 8 (32-bit), but on 64-bit platforms sizeof(Gfx) == 16
due to uintptr_t widening of Gwords.w1. This caused the emu64 segment
resolver to land in the middle of Gfx entries, producing garbage
display list commands.

Replace all hardcoded offsets with entry_index * sizeof(Gfx) so they
scale correctly on both 32-bit and 64-bit builds.
Resolved pointer truncation issues in ac_house.c and ac_ins_goki.c
where 64-bit pointers were being stored in 32-bit integer fields.
On PC, aHUS_GET_ANIMAL_P now uses the animal index to retrieve the
pointer from Save data instead of relying on the truncated value in arg1.
Similarly, aIGK_GET_ITEM_P now retrieves the FG unit from home position.
This commit addresses animation "twitching" and camera positioning bugs specific to 32-bit Linux builds by:
1. Enabling SSE2 floating-point math in the Linux 32-bit toolchain to
   avoid x87 excess precision inconsistencies.
2. Forcing 8-byte alignment for 64-bit types (s64, u64, f64) on PC
   targets to ensure consistent structure layouts across platforms.
3. Aligning the 'Mtx' structure and its conversion logic in pc_mtx.c
   with the GBI definition and ensuring 8-byte alignment.
macOS OpenGL doesn't support BC7 compressed textures.
Since the texture pack pretty much uses BC7 for everything, no custom textures would load on either macOS build.
I added a software BC7 decoder (bc7decomp by richgel999, MIT license) that kicks in automatically when the GL extension isn't available.
<malloc.h> is Linux-specific; macOS provides malloc via <stdlib.h>.
Affects all fixnes audio modules.
my_alloc_init() was casting start pointer to u32 before aligning,
silently dropping the upper 32 bits on 64-bit platforms and causing
a segfault when zelda_InitArena tried to memset the invalid address.

Use uintptr_t for pointer arithmetic throughout the TARGET_PC path.
@birabittoh birabittoh force-pushed the master branch 2 times, most recently from 3d2f41e to 1134bd6 Compare June 1, 2026 10:06
- Add <signal.h> and <setjmp.h> to pc_platform.h (Linux crash handler)
- Add _GBI_RUNTIME_PTR macro to TARGET_PC block in gbi.h
- Add pc_settings.h include to pc_audio.c (uses g_pc_settings.master_volume)
- Replace g_pc_speedhack_enabled with g_pc_fast_forward in pc_main.c / graph.c
- Replace g_pc_frame_limit_override with direct g_pc_settings.max_fps / g_pc_no_framelimit
- Fix ac_kamakura_indoor.c: broken if-block, restore counter init
- Fix ac_ins_goki.c: missing game argument to aIGK_anime_proc
- Fix ef_otikomi.c: remove dangling t variable, restore original default case
- Fix ac_nog_nabe.c: remove extra closing brace, fix indentation
- Fix ac_sugi_barbecue.c and ac_tak_stew.c: declare play before use
@birabittoh

Copy link
Copy Markdown
Author

@JPikachu @birabittoh any news on this pr?

I would like to know as well.. I have rebased it onto the latest version, but it looks like @flyngmt is not interested in merging this

@flyngmt

flyngmt commented Jun 1, 2026

Copy link
Copy Markdown
Owner

I really appreciate the work folks, it's just that this one is a pretty scary one to properly review. Normally I don't get PR's this big in my actual work, lol. I wouldn't be comfortable without properly testing it myself.

Around 0.9.4, I plan on doing a code cleanup and optimization run, it's probably the most feasible version I will start playing around with this. Currently you might have noticed that delta time update is a huge one, I don't want to blame any bugs caused by that update on your work, or vice versa.

Zorkats added a commit to Zorkats/ACGC-PC-Port that referenced this pull request Jun 16, 2026
# Conflicts:
#	src/actor/npc/ac_npc_ctrl.c_inc
@Zorkats

Zorkats commented Jun 16, 2026

Copy link
Copy Markdown

Independent validation — builds & runs on Windows x86_64 (MSYS2 UCRT64 + GCC 14.2.0)

I merged this PR onto the current flyngmt/master on my fork and ran a full validation pass on Windows 64-bit. Short version: it builds clean and plays end-to-end, including in-game audio and save/reload. Details below in case they help get this to v0.9.4.

Environment

OS Windows 11 (x86_64)
Toolchain MSYS2 UCRT64, GCC 14.2.0
SDL2 mingw-w64-ucrt-x86_64-SDL2 2.30.9
Build CMake + Ninja

Note: the README documents MINGW64 for the 64-bit build. I used UCRT64 instead and it works equally well with mingw-w64-ucrt-x86_64-SDL2. Clang was not attempted, consistent with the PR's note that 64-bit requires GCC.

Build

cmake -S pc -B pc/build64 -G Ninja \
  -DCMAKE_C_COMPILER=/ucrt64/bin/gcc.exe \
  -DCMAKE_CXX_COMPILER=/ucrt64/bin/g++.exe \
  -DCMAKE_PREFIX_PATH=/ucrt64
cmake --build pc/build64 -j

Result: AnimalCrossing.exePE32+ executable ... x86-64 (genuine 64-bit). ~4000 targets, zero errors.

One merge conflict to flag (PR needs a rebase against current master)

Merging onto today's flyngmt/master produced exactly one conflict, in src/actor/npc/ac_npc_ctrl.c_inc. Recent DT work on master parameterizes the NPC actor-class slot via a macro aNPC_ACTOR_CLASS_SLOT_SIZE (with a static_assert), while this PR hardcodes 0xC00 for TARGET_PC. On a combined 64-bit + DT build the struct is larger than either value alone, so I kept the macro form and raised it to 0xD00; the static_assert confirms it covers sizeof(NPC_ACTOR). Just a heads-up — everything else auto-merged.

What I tested (all working)

  • Boot → trademark → title screen (stable 60 FPS)
  • Full intro / Nook orientation
  • House interiors (enter/exit), NPC dialog
  • In-game audio (music + SFX)
  • Save → quit → reload (reliable across multiple cycles)
{7EED60DF-A355-42A6-853C-86486E7763CE} {BCDDA2EB-5293-487E-8DB6-8300737043D8}

Save/reload evidence (verbose log)

[PC] GCI: opened 'save/card_a/DobutsunomoriP_MURA.gci', size = 467008 (0x72040), expected 467008 (0x72040)
[PC] GCI: gameName='GAFE' company='01' fileName='DobutsunomoriP_MURA'
[PC] BSWAP verify: Save_t round-trip PASSED (148128 bytes)
[PC] BSWAP verify: keep_mail round-trip PASSED (47808 bytes)
[PC] BSWAP verify: keep_original round-trip PASSED (52384 bytes)
[PC] BSWAP verify: keep_diary round-trip PASSED (47648 bytes)
[PC] GCI save loaded successfully

Happy to share more logs or test specific scenarios if it helps. Great work on the migration.

@Zorkats

Zorkats commented Jun 16, 2026

Copy link
Copy Markdown

Hey, so I tried to take this a step further and, Linux works — built and running natively on a ROG Xbox Ally X (CachyOS)

Linux support effectively lands with the 64-bit migration (#48). Built from my fork (which has #48 merged) and ran it
natively on real handheld hardware — a ROG Xbox Ally X / CachyOS (Arch, KDE Wayland). Boots, renders, audio, gamepad,
and loads a GCI save.

Toolchain: GCC 16.1.1, CMake 4.3.3, Ninja, SDL2 2.32.70. (Same source also builds on WSL Arch GCC 15 and Windows GCC
14 — compiles across GCC 14/15/16.)

Build: pacman -S gcc cmake ninja sdl2 → cmake -S . -B build -G Ninja && cmake --build build -j → ELF 64-bit x86-64,
~4000 targets, zero errors.

Works: title screen on the handheld display · gamepad responsive · in-game audio · save/load (existing town loaded).

I hope this is useful for @flyngmt to have more security in that it was tested.

linux.proof.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants