macos: native Apple Silicon (arm64) support — address model, boot chain, 21/21 levels

Adds native arm64 macOS support on top of #88's Intel macOS layer.

The one structural change arm64 needs is an address model. The port realises
the N64's 32-bit address space *as host addresses* — DRAM at 0x70000000, cart
at 0x10000000, plus ~1700 linker-absolute symbols — which is only sound while
host addresses fit in 32 bits. Native arm64 cannot map below 4 GiB
(__PAGEZERO; a shrunken pagezero is SIGKILLed at exec; PIE is mandatory;
MAP_32BIT fails). So the whole space is relocated to a fixed host base,
PORT_ADDR_BASE (16 TiB), with portN64ToHost / portHostToN64 / PORT_N64PTR as
the conversion chokepoints. PORT_ADDR_BASE is 0 on every other platform, so
all of this is an identity there.

That relocation then surfaces a class of latent 64-bit bugs that are invisible
at base 0 — any place the decomp round-trips a pointer through a 32-bit
integer. The src/ changes here are that class: pointer-width/layout only, no
behaviour change, N64 branch textually unchanged, each documented in
docs/dev/findings.md (D298/M2).

Also: Mach-O absolute-symbol generation at the same base, #pragma weak ->
symbol equates, __x86_64__ -> PLATFORM_64BIT, Darwin crash handler/ucontext,
shm_open DRAM, the AppKit main-thread guard, and the sidecar generation that
was the real boot blocker.

Verified: 21/21 solo levels boot, render and run crash-free.
This commit is contained in:
Dan Turner committed 2026-10-04 10:50:01 +01:00
1 parent 39d4f8d088
commit d4cc71af0a
58 files changed
+1621 -329

No files matched your search

+18 -6
View File
@@ -363,12 +363,22 @@ elseif(UNIX AND NOT APPLE)
# This is the ELF analogue of the Windows build's fixed 0x140000000 base.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Ttext-segment=0x20000000")
elseif(APPLE)
# Mach-O executables normally reserve [0, 4 GiB) as __PAGEZERO. The port
# needs fixed mappings at 0x10000000 (ROM), 0x70000000 (s32-safe DRAM), and
# 0x80000000 (KSEG0 mirror), so retain null/low-pointer protection only up
# while leaving ample space before the first required mapping.
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-pagezero_size,0x10000")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
# Apple Silicon: shrinking __PAGEZERO gets the process SIGKILLed at exec
# and PIE is mandatory, so the fixed N64 mappings (0x10000000 / 0x70000000
# / 0x80000000) are impossible. The whole N64 address space is instead
# shifted to PORT_ADDR_BASE and reserved PROT_NONE by portAddrInit()
# (port/include/port_addr.h, docs/dev/MACOS-ARM64-PLAN.md).
set(PORT_ADDR_BASE 0x100000000000)
else()
# Intel: Mach-O normally reserves [0, 4 GiB) as __PAGEZERO. The port needs
# fixed mappings at 0x10000000 (ROM), 0x70000000 (s32-safe DRAM), and
# 0x80000000 (KSEG0 mirror), so retain null/low-pointer protection only up
# while leaving ample space before the first required mapping.
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-pagezero_size,0x10000")
set(PORT_ADDR_BASE 0x0)
endif()
endif()
# port/shim first: PC-only shadow headers (bondtypes.h, bondconstants.h,
@@ -475,6 +485,7 @@ if(APPLE)
OUTPUT "${SRC_ROMASSETS}"
COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
--base "${PORT_ADDR_BASE}"
"${SRC_ROMASSETS_INPUT}" "${SRC_ROMASSETS}"
DEPENDS "${SRC_ROMASSETS_INPUT}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
@@ -483,6 +494,7 @@ if(APPLE)
OUTPUT "${SRC_DRAM_SYMS}"
COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
--base "${PORT_ADDR_BASE}"
"${SRC_DRAM_SYMS_INPUT}" "${SRC_DRAM_SYMS}"
DEPENDS "${SRC_DRAM_SYMS_INPUT}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
+2 -2
View File
@@ -197,7 +197,7 @@
// These are compile time extern constants (so not "really" const), but used the same
// as the defines above, which is to index into ptr_animation_table.
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
/* D34 (docs/dev/findings.md): on N64 this segment links at VMA 0
* (ge007.ld), so &ANIM_DATA_x is the record's offset within the
* animation_data segment and game code re-bases it with
@@ -572,7 +572,7 @@ extern s32 ANIM_DATA_credits_natalya_kissing;
extern s32 ANIM_DATA_helicopter_cradle;
extern s32 ANIM_DATA_plane_runway;
extern s32 ANIM_DATA_helicopter_takeoff;
#endif /* __x86_64__ (D34) */
#endif /* PLATFORM_64BIT (D34) */
+644
View File
@@ -0,0 +1,644 @@
# macOS Apple Silicon (native arm64) port — implementation plan
Session 2026-09-18. Scope decision: **native arm64 only** (no Rosetta/x86_64
build). Nothing in this plan has run yet; §1 is measured, §2 is design, §3 is
the work. Companion: `LINUX-PORT.md` (same shape, earlier platform).
Execution model: research/design/integration items are run by the session
model ("integrator"); items marked **mechanic** are self-contained briefs for
the Sonnet-backed `.opencode/agents/mechanic.md` subagent. Every mechanic
item lists files, recipe, budget, verify. Items in the same phase that touch
disjoint files may run in parallel (dev-process.md §3).
---
## 0. Summary
The compiler is not the problem. Apple clang builds 235/237 C TUs of the
existing tree with `-fms-extensions` (in place of GCC's `-fplan9-extensions`)
plus small fixes. fast3d already selects a 4.1 Core GL context on macOS and
uses no compat or >4.1 features.
**The blocker is the port's address model.** The port realises the N64's
32-bit address space as *host* addresses: DRAM at `0x70000000` (+ KSEG0
mirror at `0x80000000`), cart at `0x10000000`, and ~1700 linker-absolute
symbols with those values; `osVirtualToPhysical` is a `u32` truncation and
`u32 → pointer` is an identity cast. That works on Windows/Linux because the
image and all mappings sit below 4 GiB. On native arm64 macOS **nothing can be
mapped below 4 GiB**: `__PAGEZERO` covers it, `-pagezero_size` gets the
process SIGKILLed, PIE is mandatory, and `MAP_32BIT` fails.
The fix (§2) is a **shifted window**: keep the N64 32-bit space intact but
place it at a fixed host base `B` (`PORT_ADDR_BASE`), so every game-visible
32-bit value is *identical* to today's Windows values and only the
`u32 → host pointer` direction changes (add `B`). `B = 0` on Windows/Linux, so
those builds are byte-for-byte unchanged. All conversions go through a
port-owned chokepoint; the residue is a compiler-driven census of raw
`u32 → pointer` casts in game code, each rewritten through a `PORT_*` macro
(the sanctioned D3x ABI/layout class — no logic change).
Phases: **M0** compile+link on macOS → **M1** address model in `port/` →
**M2** game-code cast census + rewrites → **M3** runtime bring-up (Cocoa
threading, first frame, level sweep) → **M4** packaging/CI/docs.
---
## 0b. Base change (2026-09-18, later): rebased onto PR #88 + GCC
After M0/M1 were working on Apple clang, PR #88 ("Add native Intel macOS
support", JunielKatarn) turned up: a single commit on this repo's exact base,
targeting **Intel** macOS and explicitly leaving Apple Silicon unsupported. The
arm64 work was rebased onto it rather than maintained in parallel. Branch:
**`macos-arm64-gcc`** (the earlier clang branch `macos-arm64` is superseded).
**Adopted from #88 — this deletes the corresponding work in §3 M0:**
- Homebrew GNU GCC (`gcc-16`) + libstdc++. Removes every clang workaround:
no `-fms-extensions`/`-Wno-microsoft-anon-tag`, no libc++ wrapper header
shims (the old D295), no `-D_FORTIFY_SOURCE=0`.
- `scripts/gen_macho_syms.py` — build-tree Mach-O symbol generation; the
committed `*.darwin.s` duplicates are gone.
- `scripts/strip_weak_pragmas.py` + `port/src/macho_weak_aliases.s` — the
`#pragma weak` handling, so **`src/` carries no macOS edit for it** (the old
D294 in-source `#if defined(PORT) && defined(__APPLE__)` equates are gone).
- POSIX `shm_open` DRAM backing, Darwin crash handling, and the AppKit
main-thread event-pump guard in `gfx_sdl2.cpp` (that last one was §3 M3.1).
**Kept from this plan — the arm64 delta:**
- §2's shifted-window address model (M1 / D298). `-pagezero_size 0x10000`,
the core of #88's Intel approach, is fatal on arm64 (shrinking `__PAGEZERO`
gets the process SIGKILLed), so CMake now sets it for x86_64 only and arm64
uses `PORT_ADDR_BASE`.
- D296 (`__x86_64__` → `PLATFORM_64BIT`). Without it #88's tree does not even
*link* on arm64 — 23 undefined `_ANIM_DATA_*`.
- `gen_macho_syms.py --base` (bakes `PORT_ADDR_BASE` into the absolute
symbols; `--base 0` output is byte-identical to #88's transform).
- arm64 crash registers (`__ss.__pc/__lr/__sp/__fp`) and
`_dyld_get_image_header` / `_NSGetExecutablePath`.
- All of M2 (the game-code re-basing sweep).
Mergeability consequence: the arm64 contribution is now a small additive delta
on top of #88, and `src/` has no macOS-specific toolchain/alias edits.
## 1. Measured facts (this machine: macOS 26.3, arm64, Apple clang 21, SDL2 via `sdl2-compat` 2.32)
| # | Test | Result |
|---|------|--------|
| F1 | `mmap(MAP_FIXED)` at `0x10000000` / `0x70000000` / `0x80000000`, native arm64 | **ENOMEM** — first 4 GiB is `__PAGEZERO` |
| F2 | Link with `-Wl,-pagezero_size,0x4000` (and 0x1000…0x90000000), native arm64 | links; **process SIGKILLed at exec (exit 137)** |
| F3 | `-Wl,-no_pie`, `-Wl,-image_base` | ignored ("Linking with PIE"); image lands at `0x1_0000_0000 + slide`, slide observed `0x32_0000`–`0x4EF_8000` (varies per run) |
| F4 | `mmap(MAP_32BIT)` | defined, **fails**; default thread stacks at `0x16b_xxxx_xxxx` |
| F5 | Same code as x86_64 + `-pagezero_size 0x1000` under Rosetta | all fixed maps succeed (not our target; recorded for completeness) |
| F6 | `mmap(MAP_FIXED)` at `B + n64addr` for `B ∈ {1,2,3,4} << 32` | all succeed — **but `MAP_FIXED` silently replaces existing mappings on macOS** (no `MAP_FIXED_NOREPLACE`), so success ≠ range was free. A 64 MiB `malloc` was observed at `0x4_8400_0000`. |
| F7 | Non-clobbering 4 GiB `PROT_NONE` reservation via `mach_vm_map(VM_FLAGS_FIXED)` (no `OVERWRITE`) | `0x3<<32` free (this run); `0x2,0x4,0x8,0x10,0x20,0x40 <<32` **occupied** (libmalloc/VM regions, varies); **`0x100_0000_0000` (1 TiB), `0x400_0000_0000`, `0x1000_0000_0000` (16 TiB) reserved cleanly**, DRAM+cart carved inside OK |
| F8 | Hinted `mmap` without `MAP_FIXED` | hint ignored (relocated to `0x70_0000_0000`) — cannot rely on hints; must reserve |
| F9 | `shm_open`+`ftruncate`+2×`mmap(MAP_SHARED\|MAP_FIXED)` at `B+0x70000000` / `B+0x80000000` | works; alias verified (`memfd_create` replacement) |
| F10 | `.set _cfb_16, 0x470000000` (64-bit-valued absolute symbol) referenced from C | links, `nm` type `A`, **no rebase fixups** (`dyld_info -fixups`) → ASLR-stable; clang emits GOT loads |
| F11 | `-fplan9-extensions` | unknown argument (hard error). `-fms-extensions` accepts `inherits struct`; derived→base pointer passing becomes `-Wincompatible-pointer-types` (already demoted) |
| F12 | `-fpermissive` (C), `-Og`, `-Wno-unused-but-set-variable`, `-fno-pie` | accepted (`-fpermissive` is a silent no-op in C) |
| F13 | `-Wl,--disable-dynamicbase`, `-Wl,-Ttext-segment=` | ld64 unknown options (already not applied on APPLE) |
| F14 | `.section .data` in both `.s` files | assembler error; `.data` works. `.global LameE` (88 `L*` names in `romassets_u.s`) → "non-local symbol required" until `_`-prefixed |
| F15 | `#pragma weak X = Y` (sinf.c, cosf.c, objective_status.c, lv.c, spectrum.c) | Darwin emits a *local* alias: cross-TU users get undefined symbol; same-TU `extern` + use → "reference to X is ambiguous" (lv.c:603-606, spectrum.c:266) |
| F16 | `-fsyntax-only` sweep, 237 C TUs, with `-fms-extensions -D_FORTIFY_SOURCE=0` + corrected host-header shim paths | **235/237 pass** (fails: lv.c, spectrum.c — F15). 4 fast3d `.cpp` TUs fail on libc++ header shadowing (`include/math.h`, `limits.h`, `assert.h` ahead of the SDK) |
| F17 | `port/include/pc_protos.h:34` is gated on `__x86_64__` | on arm64 all ~400 D38 prototypes vanish → 45–63 implicit-declaration warnings per big TU (bg.c, chrai.c, propobj.c, front.c, boss.c) = silent pointer-return truncation. 23 game/asset sites use the same gate |
| F18 | GL | fallback table lands on `{4,1,CORE}` on macOS; GLSL `#version 410 core`; VAO created for Core; no compat/>4.1 entry points. 2.1 compat is **not** enough (GLSL 1.30 min, FBO/blit/MSAA, `GL_DEPTH_CLAMP`) |
---
## 2. Design: the shifted-window address model
### 2.1 Invariant
Let `B = PORT_ADDR_BASE` (compile-time, per platform). Every host pointer that
game code may truncate to 32 bits lives in the window `W = [B, B + 4 GiB)`,
at host address `B + n64addr`. Therefore:
- `(u32)host_ptr` for any `host_ptr ∈ W` yields **exactly today's Windows
value**. The pointer→u32 direction needs no game-code edits for in-window
pointers.
- `u32 → host pointer` becomes `B + u32`. This is the only direction that
changes, and it is funnelled through one chokepoint.
- On Windows/Linux `B = 0`: every chokepoint is an identity, behaviour and
codegen are unchanged.
### 2.2 N64-space layout inside `W` (window offsets; unchanged from today)
| Range | Content | Host mapping |
|---|---|---|
| `[0x0000_0000, 0x1000_0000)` | segmented DL addresses (never host memory) | none (reserved `PROT_NONE`) |
| `[0x1000_0000, 0x2000_0000)` | cart image + sidecars (`CART_BASE`) | `MAP_FIXED` carve (romdata.c) |
| `[0x4000_0000, 0x7000_0000)` | **image-relative encoding** (§2.4) — virtual, never mapped | none |
| `[0x7000_0000, +8 MiB)` | DRAM V1 | `shm_open` view 1 (dram.c) |
| `[0x8000_0000, +8 MiB)` | DRAM V2 / KSEG0 mirror | `shm_open` view 2 |
| `[0xA000_0000, 0xC000_0000)` | game-thread stacks, 8 MiB + guard page each (replaces `MAP_32BIT`) | `MAP_FIXED` carve (libultra.c) |
| everything else | reserved, unmapped | `PROT_NONE` |
`B` proposal: **`0x1000_0000_0000` (16 TiB)** — reserved cleanly (F7), far
above libmalloc's regions (`0x1..0x8 <<32`, observed) and the mmap hint region
(`0x70_0000_0000`), below `fast3d_ptr_ok`'s `0x8000_0000_0000` bound. Fallback
candidate `0x100_0000_0000`. Item **M1.1** confirms on a second machine and
fixes the constant.
### 2.3 Startup contract
`portAddrInit()` is the **first thing in `main()`** (before SDL, before any
large allocation): `mach_vm_map(task, &B, 4 GiB, VM_FLAGS_FIXED, PROT_NONE)`.
Failure is fatal with a clear message — the same contract as the Windows
build's `0x140000000` load-base check (`main.c:176`). Once reserved, carving
sub-ranges with `MAP_FIXED` is safe (we own the range). No heap-copy
fallbacks on macOS: `romdata` cart map failure is fatal, not degraded.
### 2.4 Chokepoint API — `port/include/port_addr.h` (new)
```c
#define PORT_ADDR_BASE /* 0 on Windows/Linux; B on PLATFORM_MACOS && PLATFORM_ARM */
/* u32 (N64/"physical") -> host pointer. */
static inline void *portN64ToHost(u32 a) {
if (a >= 0x40000000u && a < 0x70000000u) /* image-relative (D131 generalised) */
return (void *)(portImageBase() + (a - 0x40000000u));
return (void *)(PORT_ADDR_BASE + (uintptr_t)a);
}
/* host pointer -> u32. In-window: window offset. In-image: 0x40000000 + image offset. */
static inline u32 portHostToN64(const void *p);
/* Cast-site macro for game code (D3x class). Identity semantics at B == 0. */
#define PORT_N64PTR(T, expr) ((T *)portN64ToHost((u32)(expr)))
```
Rewired to it (all in `port/`): `osVirtualToPhysical`/`osPhysicalToVirtual`
(`libultra.c:1442-1443`), `OS_K0_TO_PHYSICAL`/`OS_PHYSICAL_TO_K0`
(`port/shim/PR/os.h:34,37` — subtract/add `B + 0x70000000`), `PHYS_TO_K0`
(`port/shim/PR/R4300.h:25`, `port/shim/R4300.h:14`), fast3d `seg_addr`
(`gfx_pc.cpp:2881-2935` — replace the `mod_hi` block with the image-relative
rule; add `B` to the `< 0x800000` and pass-through returns), the fast3d
range classifier (`gfx_pc.cpp:630-635` — compare `p - B`), `G_MW_SEGMENT`
(`:2324-2327`) and `G_MW_NUMLIGHT` (`:2317`), mixer `osPhysicalToVirtual`
users (`mixer.c:147,152,297`), `piServiceDma` (`libultra.c:1001`),
`dramHostAddrValid` (`libultra.c:909-911`), `romdataIsCartAddr`
(`romdata.c:441-451`), `n64stubs.c:94-107` (`0x70700000` literal).
**Why image-relative reproduces D131 exactly on Windows:** the image base is
`0x1_4000_0000`, so `0x40000000 + (p - image_base) == (u32)p` — the current
truncation result. On Linux (`-Ttext-segment=0x20000000`) `&sym` currently
passes through `seg_addr` untouched; under the new rule it round-trips
through `0x4xxxxxxx` to the same pointer. No behaviour change either way.
### 2.5 Absolute symbols
`dram_syms.s` (3 symbols) and `romassets_<region>.s` (1685 cart symbols) are
generated with `B +` added on Darwin, Mach-O syntax (`.data`, `_` prefix).
Verified viable by F10. The generator (`scripts/gen_romassets.py`) grows a
`--darwin --base 0x...` mode; `B` is defined in exactly two places
(`port_addr.h` and the CMake variable that feeds the generator) with a
`_Static_assert`/CMake check that they agree.
### 2.6 The residue: raw casts in game code
Game code sites that turn a `u32` back into a pointer without going through a
chokepoint are the only thing the model cannot fix by construction. Grep
estimates (heuristic, noisy): 117 `(u32|s32)&sym` in 21 files, ~278
`(T *)obj->field`-shaped casts, 7 `romptr_t`, 5 existing `PORT_PTRADD`. The
authoritative census is the compiler (item **M2.1**): clang's
`-Wint-to-pointer-cast`, `-Wpointer-to-int-cast` and `-Wint-conversion`
(all warnings, none demoted to off) list every site precisely once M0 links.
Each `u32 → pointer` site becomes `PORT_N64PTR(T, expr)`; each
`&image_symbol → u32` site becomes `portHostToN64(&sym)`; in-window
`ptr → u32` truncations are left alone. Every edit is identity at `B = 0`.
### 2.7 What this model deliberately does NOT do
- No PD-style relocatable/offset addressing rewrite of game structures.
- No change to `Gwords {uintptr_t w0, w1}` (already 64-bit-safe).
- No attempt to place the executable inside `W` (F3: not controllable).
---
## 3. Work items
Sizes: **S** ≤1 h, **M** 1–3 h, **L** half-day+. "mechanic" = Sonnet subagent
with the brief below; "integrator" = session model. Budgets are per
dev-process.md §1; on expiry: revert probes, leave the tree buildable, write up.
Common to every item — **READ FIRST:** this doc §2; `docs/porting-notes.md`
(headers); `AGENTS.md` non-negotiables. **CONSTRAINTS:** no game-logic
changes; `src/`/`assets/` edits only where an item lists them and only in the
sanctioned mechanical classes; N64 build (`Makefile`, `tools/`, `rsp/`, `ld/`)
untouched; new findings appended to `docs/dev/findings.md` §F/§H under the
next free `Dxx` (last used at time of writing: D293) and indexed at the top of
§F. **VERIFY** for build-affecting items always ends with
`./build-pc.sh ntsc-final` (or the explicit target-only build the item names).
### Phase M0 — compile and link on macOS arm64 (no runtime expected)
Goal: `./build-pc.sh ntsc-final` produces `build-pc/ge007.*` on this Mac.
`B` is still 0 in this phase (address model stubbed), so the binary will not
boot; the milestone is a clean link + the M2 census becoming available.
| ID | Title | Who | Size | Deps | Files |
|---|---|---|---|---|---|
| M0.1 | CMake: Apple-clang toolchain path | mechanic | M | — | `CMakeLists.txt`, `cmake/*.cmake`, `build-pc.sh`, `docs/building.md` |
| M0.2 | `__x86_64__` → `PLATFORM_64BIT` as the 64-bit-PC gate | mechanic | S | — | `port/include/pc_protos.h`, `port/include/platform.h`, + the 23 game/asset sites listed |
| M0.3 | Darwin mode for generated assembly | mechanic | M | M0.1 | `scripts/gen_romassets.py`, `port/src/dram_syms.s` (→ generated), `CMakeLists.txt` (gen invocation) |
| M0.4 | `#pragma weak X = Y` on Darwin | integrator → mechanic | S | — | `src/libultra/gu/sinf.c`, `cosf.c`, `src/game/objective_status.c`, `lv.c`, `spectrum.c`, `port/src/darwin_compat.c` (new) |
| M0.5 | Header/libc clashes on Darwin | mechanic | M | M0.1 | `port/include/pc_protos.h`, `port/src/pc_netorder.c`, `port/shim/*`, `port/src/{romdata,romconvert,pccg,pcmodels,fs}.c`, `port/src/system.c` |
| M0.6 | fast3d C++ TUs vs libc++ header shadowing | mechanic | M | M0.1 | `port/shim/` (new C++-route shims for `math.h`/`limits.h`/`assert.h`), `CMakeLists.txt` |
| M0.7 | macOS branches: `crash.c`, `system.c` | mechanic | M | — | `port/src/crash.c`, `port/src/system.c` |
| M0.8 | macOS stubs for `dram.c`/`romdata.c`/`libultra.c` low-stack (compile-only) | mechanic | S | — | `port/src/dram.c`, `port/src/romdata.c`, `port/src/libultra.c` |
| M0.9 | Link-check + first `findings.md` batch | integrator | S | M0.1–M0.8 | `docs/dev/findings.md` |
**M0.1 — CMake: Apple-clang toolchain path.**
Recipe: (a) detect clang (`CMAKE_C_COMPILER_ID STREQUAL "Clang"` or
`AppleClang`) and in the `if(NOT MINGW)` block at `CMakeLists.txt:289-298`
emit `-fms-extensions -Wno-microsoft-anon-tag` for clang instead of
`-fplan9-extensions`; drop `-fpermissive` for clang; keep the GCC branch
intact. (b) For clang add `-Wno-error=implicit-int
-Wno-error=incompatible-function-pointer-types` next to the existing
`-Wno-error=` set (`:273-277`); do **not** silence `-Wint-to-pointer-cast`,
`-Wpointer-to-int-cast`, `-Wint-conversion` (they are the M2 census).
(c) `add_definitions(-D_FORTIFY_SOURCE=0)` on APPLE (F16: the N64
`sprintf` prototype vs `__builtin___sprintf_chk`). (d) Host-header shim
derivation at `:165-205`: on APPLE derive from
`execute_process(xcrun --show-sdk-path)` / `CMAKE_OSX_SYSROOT` →
`${SDK}/usr/include/{string,sched,stdlib}.h` instead of
`${_PORT_GCC_DIR}/../include`. (e) `:39-45`: set
`CMAKE_OSX_DEPLOYMENT_TARGET 11.0` when `CMAKE_SYSTEM_PROCESSOR` is
`arm64`/`aarch64` (currently keys off empty `CMAKE_OSX_ARCHITECTURES` →
10.13). (f) `find_program(gcc)` at `:27-37` — prefer `clang` on APPLE and
update the comment (it says clang rejects `inherits`; F11 shows it does not
with `-fms-extensions`). (g) `build-pc.sh`: brew line already right; add a
note that `zlib` is keg-only (CMake's `find_package(ZLIB)` finds the SDK
zlib — verify, and if so say brew zlib is optional). Budget: 6 configure/build
cycles. Verify: `cmake -S . -B build-pc -DROMID=ntsc-final` succeeds; `cmake
--build build-pc --target ge007 -- -k 2>&1 | tee /tmp/m01.log`; report the
distinct remaining error classes (expected: F14 asm, F15 pragma weak, F17
implicit decls, libc++ shadowing, `memfd_create`, `crashDumpThreads`) — those
belong to M0.2–M0.8, not this item.
**M0.2 — `__x86_64__` → `PLATFORM_64BIT`.** Sites (from
`grep -rn __x86_64__ src assets include port`): `port/include/pc_protos.h:34`
(the gate for the whole D38 header — critical, F17); `src/memp.c:66`;
`src/music.c:55,688,711`; `src/game/objecthandler.c:7` (D40 — N64 branch
overruns `.bss` by 12 KB on any 64-bit host); `src/game/initunk_005450.c:41`;
`src/game/rsp.c:276`; `src/game/image_bank.c:170`;
`assets/animationtable_data.h:200-575` (D34); `src/audi.c:10,666,734`;
`src/libultra/audio/load.c:26,200,393,496`; `synthesizer.c:23,125`;
`synsetfxmix.c:22`, `synsetpan.c:22`, `synsetvol.c:22`; `src/save.c:24`;
`port/src/system.c:177` (keep — that one really is x86: `_mm_pause`). Recipe:
replace `defined(__x86_64__)` with `defined(PLATFORM_64BIT)` at each listed
site (spelling change only; every site is an existing, documented port-class
edit); ensure `platform.h` is reachable from those TUs (it is included via
`versioninfo.h`/`-include`? — check; if not, `pc_protos.h`-style
`-include` or add `#include "platform.h"` to `port/shim/bondconstants.h`).
`CMakeLists.txt:217-219` already defines `PLATFORM_64BIT=1` for aarch64 via
`cmake/TargetArch.cmake`. Budget: 2 build cycles. Verify: `grep -rn
__x86_64__ src assets include port` shows only `system.c:177`; build of
`bg.c`, `chrai.c`, `propobj.c`, `front.c`, `boss.c` shows **0**
`-Wimplicit-function-declaration` (was 45–63 each).
**M0.3 — Darwin mode for generated assembly.** Recipe: add
`--darwin` (and `--base 0xHEX`, default 0) to `scripts/gen_romassets.py`:
emit `.data` not `.section .data`; prefix every symbol with `_`; emit `.set
_sym, (base + value)` — 64-bit values are fine (F10). Regenerate
`port/src/romassets_u.s` (and `_e`/`_j` if the generator supports them — note
they are currently absent, `CMakeLists.txt:417-420`). Convert
`port/src/dram_syms.s` into generator output (or a tiny Darwin twin selected
by CMake) with the same `--base`. Wire the CMake invocation (pass
`PORT_ADDR_BASE` from a cache var; default 0 in M0). Keep ELF output
byte-identical when `--darwin` is absent (diff the regenerated file against
git). Budget: 4 cycles. Verify: `nm build-pc/CMakeFiles/.../romassets_u.s.o
| head` shows `A`-type `_`-prefixed symbols; `nm ... | grep -c ' A '` = 1685;
`dyld_info -fixups build-pc/ge007.* | grep -c romassets-symbol-name` = 0 once
linked (M0.9).
**M0.4 — `#pragma weak X = Y` on Darwin.** Integrator first (30 min):
read the five sites (`sinf.c:33-34`, `cosf.c:33-34`, `objective_status.c:162`
+ consumer `chrai.c:41,2538`, `lv.c:208-216,603-606`, `spectrum.c:49-50,266`)
and decide per site the minimal semantics-preserving form under
`#if defined(PORT) && defined(__APPLE__)`: for `sinf`/`cosf` a strong
definition in a **new port file** `port/src/darwin_compat.c`
(`float sinf(float x){return __sinf(x);}` …) so the 25 game TUs keep binding
to Rare's polynomial, not libSystem's (fidelity); for the three game-file
aliases, a `PORT`-gated `#define X Y` or wrapper — record the choice as a
`Dxx` (symbol-aliasing mechanism, ABI class). Then mechanic applies it.
Budget: 3 cycles. Verify: `lv.c`, `spectrum.c` compile; link has no
undefined `objectiveGetStatus_WEAK`; `nm build-pc/ge007.* | grep -E
' T _(sinf|cosf)$'` shows both defined in the executable.
**M0.5 — Header/libc clashes.** Recipe: (a) `ntohl/ntohs`: on APPLE
`<sys/_endian.h>` defines them as macros with `__uint32_t` prototypes;
guard the K&R declarations in `pc_protos.h:54-60` and the definitions in
`pc_netorder.c:24-32` with `#if !defined(__APPLE__)` (the game's own macros
are already `#undef`'d in `port/shim/bondconstants.h:37-38`). (b) K&R
redeclarations spelling `size_t` as `unsigned long long`
(`romdata.c:25`, `romconvert.c:28`, `pccg.c:24`, `pcmodels.c:26`,
`fs.c:18`) → `size_t` (identical on all shipping platforms; hard error the
moment the SDK prototype is visible). (c) `system.c:26` `_POSIX_C_SOURCE
199309L` hides `readlink` on Darwin → add `_DARWIN_C_SOURCE` on APPLE.
(d) Anything else M0.1's log lists under this class. Budget: 3 cycles.
Verify: the listed TUs compile warning-free for these classes.
**M0.6 — fast3d C++ vs libc++.** Recipe: the four `port/fast3d/*.cpp` TUs
fail because `include/math.h`, `include/limits.h`, `include/assert.h`
shadow the SDK ahead of libc++'s `<cmath>`/`<climits>`/`<cassert>` (F16).
Add C++-routed shims in `port/shim/` following the existing pattern
(`port/shim/stdlib.h:16-30`: `#ifdef __cplusplus` → host header by absolute
SDK path via the CMake-generated `host*.h`, else N64 header). Alternative if
that fights libc++: compile the four fast3d TUs with a private include order
(`target_include_directories` on an OBJECT library, SDK first). Budget: 5
cycles. Verify: all four `.cpp` TUs compile.
**M0.7 — macOS branches in `crash.c` and `system.c`.** Recipe (crash.c):
change the `PLATFORM_LINUX` block guard (`:306-473`) to `PLATFORM_LINUX ||
PLATFORM_MACOS`; replace the glibc `uc_mcontext.gregs[REG_*]` reads
(`:344-358, 413-417`) with a `PLATFORM_MACOS && PLATFORM_ARM` variant
reading `uc->uc_mcontext->__ss.__pc/__fp/__sp/__lr/__x[]`
(`<mach/arm/_structs.h>`); keep `backtrace`/`backtrace_symbols`/`dladdr`;
ensure `crashDumpThreads` is defined (it is referenced by
`libultra.c:264`); note in the log that symbolication is
`atos -o ge007 -l <slide>` and print `_dyld_get_image_vmaddr_slide(0)` at
crash time. Recipe (system.c): `sysImageBase()` → `(uintptr_t)
_dyld_get_image_header(0)` on APPLE; `sysGetExeDir()` → `_NSGetExecutablePath`
+ `dirname` (or `SDL_GetBasePath`) instead of `"."`; `$S/` resolution at
`:260` (`/proc/self/exe`) → same helper. Budget: 4 cycles. Verify: both TUs
compile; `nm | grep crashDumpThreads` defined once.
**M0.8 — compile-only macOS stubs (address model lands in M1).** Recipe:
`dram.c`: add a `PLATFORM_MACOS` branch that compiles (`shm_open` skeleton
per F9, addresses still `0x70000000`/`0x80000000` — will fail at runtime,
expected); `romdata.c`: `MAP_FIXED_NOREPLACE` path already `#ifdef`'d — no
change unless the log says otherwise; `libultra.c:417-438`
`portAllocLowStack`: compiles as-is (`MAP_32BIT` exists). Budget: 2 cycles.
Verify: link completes.
**M0.9 — link-check + findings batch (integrator).** Run the AGENTS.md
verification ritual (`/linkcheck`): undefined/duplicate symbols across the
compiled set; record M0's findings as one `findings.md` batch (F11–F17 each
get a `Dxx` row or are folded into one "macOS toolchain" row) and update
`docs/building.md` "macOS: compiles, does not run yet (address model: M1)".
### Phase M1 — the address model in `port/`
Goal: the macOS binary boots to the first frame with `B ≠ 0`, with the
game-code census still pending (expect crashes at un-rewritten cast sites —
those are M2). All items here are `port/`-only.
| ID | Title | Who | Size | Deps | Files |
|---|---|---|---|---|---|
| M1.1 | Fix `B`; write `port_addr.h` + `portAddrInit()` | integrator | S | M0.9 | `port/include/port_addr.h` (new), `port/src/main.c`, `CMakeLists.txt` |
| M1.2 | Rewire OS chokepoints | mechanic | M | M1.1 | `port/src/libultra.c`, `port/shim/PR/os.h`, `port/shim/PR/R4300.h`, `port/shim/R4300.h`, `port/src/n64stubs.c` |
| M1.3 | DRAM double-map + cart map + stacks inside `W` | mechanic | M | M1.1 | `port/src/dram.c`, `port/src/romdata.c`, `port/src/libultra.c` (`portAllocLowStack`) |
| M1.4 | fast3d `seg_addr` / classifier / moveword on `B` | mechanic | M | M1.1 | `port/fast3d/gfx_pc.cpp` |
| M1.5 | Mixer + PI DMA + validity helpers on `B` | mechanic | S | M1.1 | `port/src/mixer.c`, `port/src/libultra.c` (`piServiceDma`, `dramHostAddrValid`), `port/src/romdata.c` (`romdataIsCartAddr`) |
| M1.6 | Absolute symbols regenerated with `B` | mechanic | S | M0.3, M1.1 | generated `.s` via CMake var |
| M1.7 | Boot attempt + triage | integrator | M | M1.2–M1.6 | — |
**M1.1 (integrator).** Confirm `B` on a second Mac if available (run the
F7 probe: reserve 4 GiB `PROT_NONE` at candidates via `mach_vm_map
VM_FLAGS_FIXED`); fix `PORT_ADDR_BASE = 0x1000_0000_0000` (fallback
`0x100_0000_0000`). Write `port_addr.h` per §2.4 with `portImageBase()`
(`_dyld_get_image_header(0)` on macOS; `sysImageBase()` elsewhere — on
Windows this must equal `0x140000000` so the image-relative rule reproduces
D131 exactly; assert it). `portAddrInit()` as §2.3, called first in
`main()`; on non-macOS it is a no-op. Expose `PORT_ADDR_BASE` to CMake
(`-DPORT_ADDR_BASE=` cache var, APPLE default the constant, else 0) so M1.6
can feed the generator; add a `_Static_assert` tying the two.
**M1.2 (mechanic).** Recipe: `osVirtualToPhysical` → `portHostToN64`,
`osPhysicalToVirtual` → `portN64ToHost` (`libultra.c:1442-1443`);
`OS_K0_TO_PHYSICAL(x)` → `(u32)((uintptr_t)(x) - (PORT_ADDR_BASE +
0x70000000))`, `OS_PHYSICAL_TO_K0(x)` → `portN64ToHost(x)`
(`port/shim/PR/os.h:34,37`); `PHYS_TO_K0` likewise (`port/shim/PR/R4300.h:25`,
`port/shim/R4300.h:14`); `n64stubs.c:94-107` `0x70700000` literal →
`portN64ToHost(0x70700000)`. Budget: 3 cycles. Verify: Windows/Linux
semantics unchanged is provable by inspection (`B = 0` ⇒ identity) — state
it; macOS builds.
**M1.3 (mechanic).** Recipe: `dram.c` macOS branch: `shm_open` (unique
name, `shm_unlink` immediately) + `ftruncate(8 MiB)` + two
`mmap(MAP_SHARED|MAP_FIXED)` at `B+0x70000000` and `B+0x80000000` (F9); fatal
on any failure (no fallback). `romdata.c`: on macOS `mmap(MAP_FIXED)` at
`B+CART_BASE` (safe post-reservation), fatal on failure — do **not** take the
heap-copy path on macOS (comment why: window invariant). `libultra.c`
`portAllocLowStack`: macOS branch carves 8 MiB + 16 KiB guard per thread from
`[B+0xA0000000, B+0xC0000000)` with a simple bump allocator + free list;
`pthread_attr_setstack` as today. Budget: 4 cycles. Verify: a debug log line
per mapping with the host address; run `build-pc/ge007 -level_09` far enough
to see "DRAM V1 @0x1000_7000_0000 … cart @ … stacks @ …" (crash afterwards is
expected in M1).
**M1.4 (mechanic).** Recipe (`gfx_pc.cpp`): `seg_addr` (`:2881-2935`) —
the `w1 < 0x800000` branch returns `portN64ToHost(w1 + 0x80000000)`; the
D131 `mod_hi` block is replaced by the image-relative rule (`0x40000000 ≤ w1
< 0x70000000` → `portN64ToHost(w1)`); the final pass-through stays for
full-width host pointers but a `w1 < 0x1_0000_0000` value there means
"in-window N64 address" → `portN64ToHost`. `G_MW_SEGMENT` (`:2324-2327`)
and `G_MW_NUMLIGHT` (`:2317`) same treatment. Range classifier
(`:630-635`): compare `(uintptr_t)p - PORT_ADDR_BASE` against the cart and
DRAM windows. `fast3d_ptr_ok`/`addr_bad` bounds: unchanged (16 TiB <
128 TiB). Budget: 3 cycles. Verify: builds; on Windows semantics unchanged
(identity) — state the argument per site.
**M1.5 (mechanic).** `mixer.c:147,152,297` already call
`osPhysicalToVirtual` → covered by M1.2; check `mixer.h`'s `u32 dramAddr`
ABI needs nothing. `piServiceDma` (`libultra.c:1001`): `memcpy` source from
`portN64ToHost(srcPA)`. `dramHostAddrValid` (`:909-911`) and
`romdataIsCartAddr` (`romdata.c:441-451`): ranges offset by `B`. Budget: 2
cycles.
**M1.7 (integrator).** Boot `-level_09` (the standard sweep level); triage
the first crash against the census (M2.1), which by now exists. Expect the
first failures at `(T *)u32field` sites in game code.
### Phase M2 — game-code cast census and rewrites (the D3x class)
| ID | Title | Who | Size | Deps | Files |
|---|---|---|---|---|---|
| M2.1 | Compiler census | mechanic | S | M0.9 | none (report only) |
| M2.2 | Classify census → work packets by file | integrator | M | M2.1 | `docs/dev/MACOS-ARM64-PLAN.md` (this doc, §3 table) |
| M2.3a–n | Rewrite packets (one per file group, disjoint) | mechanic ×N (parallel) | S–M each | M2.2 | per packet |
| M2.4 | Re-run census; assert zero unclassified | mechanic | S | M2.3 | — |
**M2.1 — census (mechanic).** Recipe: `cmake --build build-pc -- -k 2>&1 |
tee /tmp/census.log`; extract `grep -E 'warning: .*\[-W(int-to-pointer-cast|
pointer-to-int-cast|int-conversion)\]' /tmp/census.log | sort -u` into
`/tmp/census.txt`; also grep `src/ assets/` for `(u32)&`, `(s32)&`,
`romptr_t`, `PORT_PTRADD`; produce a table `file:line | direction (u32→ptr /
ptr→u32 / implicit) | operand kind (field / &global / local / call result)`.
No edits. Budget: 45 min.
**M2.2 — classify (integrator).** Per site decide: **(a)** `u32 → pointer`
where the `u32` holds an N64 address (DRAM/cart/stack) →
`PORT_N64PTR(T, expr)`; **(b)** `&global → u32` (image pointer) →
`portHostToN64(&sym)` (identical value on Windows); **(c)** in-window
`pointer → u32` truncation → leave; **(d)** ROM-serialized field (D3x) →
already handled or `PORT_PTRADD`/`romptr_t` pattern; **(e)** genuine
integer (not an address) → leave. Group (a)+(b) into packets by file so
mechanics never collide (dev-process.md §3); each packet lists exact
`file:line` sites and the replacement. Record the class counts in this doc.
**M2.3 packets (mechanic, parallel).** Per packet brief: FILES = the
packet's files only; recipe = the per-site replacement table; every edit is
one of the two macro forms — no other change; add a one-line `/* D3x/M2:
window-model cast, identity at PORT_ADDR_BASE==0 */`-style comment only
where the file has no adjacent D3x comment already. Budget: 2 cycles per
packet. Verify: packet TUs compile; census diff shows the packet's sites
gone; `./build-pc.sh ntsc-final` green.
### Phase M3 — runtime bring-up
| ID | Title | Who | Size | Deps | Files |
|---|---|---|---|---|---|
| M3.1 | Cocoa main-thread hygiene | mechanic | M | M0 | `port/fast3d/gfx_sdl2.cpp`, `port/src/video.c`, `port/src/input.c` |
| M3.2 | Two Core-profile GL bugs + MSAA clamp | mechanic | S | M0 | `port/fast3d/gfx_opengl.cpp`, `port/src/video.c` |
| M3.3 | First frame → intro → menu → `-level_09` | integrator | L | M1.7, M2.4, M3.1 | triage only |
| M3.4 | arm64 float→int semantics check | integrator | M | M3.3 | `docs/dev/findings.md` |
| M3.5 | Level sweep (21 levels, unattended window) | mechanic (runs) + integrator (triage) | L | M3.3 | `docs/dev/LEVEL-STATUS.md` |
| M3.6 | Weak-memory-ordering audit of cross-thread flags | integrator | M | M3.3 | `port/src/video.c`, `optionsoverlay.c`, `libultra.c` |
**M3.1 (mechanic).** Recipe: remove the render-thread `SDL_PollEvent` pump
(`gfx_sdl2.cpp:311-360`, called from `gfx_pc.cpp:3301`) — the host thread
already pumps (`video.c:502-591`); route Alt+Enter through
`videoRequestFullscreen` (`video.c:298-309`); replace the render-thread
`exit(0)` calls (`gfx_sdl2.cpp:322/348/356`) with a quit request the host
loop honours. Marshal `SDL_SetRelativeMouseMode`/`SDL_ShowCursor`
(`input.c:1227,1256,1310,1313`, reached from render + game threads) onto the
host thread via the existing `winReq*` queue. `SDL_GameControllerUpdate`
(`input.c:622`, game thread) — move to the host pump, snapshot state under
the existing lock. Budget: 5 cycles (Windows/Linux behaviour must be
unchanged — this is a correctness fix everywhere). Verify: builds; on macOS
no `NSInternalInconsistencyException`/main-thread assertions in the log once
M3.3 boots.
**M3.2 (mechanic).** `gfx_opengl.cpp:1271` binds the vector *index* instead
of `.fbo` (cf. correct `:1335`) — fix; `:1328` `glReadBuffer(GL_FRONT)` when
`use_back=false` (`video.c:722`) is undefined on Cocoa → read the back buffer
or the FBO; clamp `gfx_msaa_level` to `GL_MAX_SAMPLES` before `:1187/:1199`.
Budget: 2 cycles.
**M3.4 (integrator).** arm64 `fcvtzs` **saturates** and yields 0 for NaN;
x86 `cvttss2si` yields `0x80000000` for overflow and NaN; MIPS yields
`0x7FFFFFFF`. Sites validated against x86 behaviour: `floorFloatToInt`
(`src/game/math_floor.c:42`, 19 call sites), `FTOFIX32` in `guMtxF2L`
(`include/PR/gu.h:38` — also `long` = 64-bit on LP64), D73/D155/D156 guards
(`src/game/model.c`). Re-read each; where behaviour differs for
out-of-range/NaN inputs, decide whether a port-side helper is needed to
match the x86-validated behaviour (a `port/` change; no game-code edit).
Record as a `Dxx`.
### Phase M4 — packaging, CI, docs
| ID | Title | Who | Size | Files |
|---|---|---|---|---|
| M4.1 | `.app` bundle target + `Info.plist` + `$S/` under `~/Library/Application Support/ge007` when bundled | mechanic | M | `CMakeLists.txt`, `port/src/system.c`, `port/src/romconvert.c` |
| M4.2 | GitHub Actions `macos-14` (arm64) compile job (mirror of the Ubuntu job) | mechanic | S | `.github/workflows/ci.yml` |
| M4.3 | `docs/building.md` macOS section; README "Status"; AGENTS.md build note (currently says MSYS2 only) | mechanic | S | docs |
| M4.4 | Bundle script (`bundle-mac.sh`, mirrors `bundle-win.sh`; reuse `prepare-assets.py`) | mechanic | M | scripts |
---
## 4. Decisions needed from a human
1. **`B` value** — `0x1000_0000_0000` proposed (F7). Needs one more machine's
probe before M1.1 fixes it. If no second Mac: accept the fatal-on-failure
contract and revisit if a user report shows the range occupied.
2. **`#pragma weak` handling (M0.4)** touches three game files with a
`PORT`-gated alias/wrapper. Sanctioned as ABI/linker-mechanism class?
(Recommendation: yes, documented as one `Dxx`.)
3. **Heap-copy fallback on macOS = fatal** (§2.3). Confirms we never run
degraded on macOS; a Mac that cannot reserve 4 GiB `PROT_NONE` at `B`
cannot run the port. (Recommendation: yes; it costs nothing — `PROT_NONE`
reservations are free.)
4. **M3.1 changes Windows/Linux behaviour too** (removing the render-thread
event pump). Recommendation: yes — it is an SDL-rules violation on every
platform; verify Windows once after.
## 5. Risks (ranked)
1. **Census size (M2).** If the compiler census exceeds a few hundred
`u32 → pointer` sites, M2 becomes the dominant cost. Mitigation: the
rewrites are mechanical and file-partitioned; run 4–6 mechanics in parallel.
2. **Game code keeping host pointers in `u32` fields *implicitly*** (no cast,
`-Wint-conversion`): each is a latent truncation today too; the census
catches them, but classification needs judgement (integrator time).
3. **Pointers reaching game code from host allocations outside `W`** (e.g. a
port-side `malloc` result handed into a game struct) — invisible to the
census. Mitigation: M1.7/M3.3 triage; `dramHostAddrValid`-style debug
assert in `portHostToN64` (env-gated) that logs any out-of-window,
out-of-image pointer.
4. **arm64 float→int and weak memory ordering** (M3.4, M3.6): subtle,
non-crashing divergences; needs framediff against the Windows reference.
5. **SDL2 on macOS is `sdl2-compat` over SDL3** (brew default): behaviour
differences in relative mouse mode / HiDPI are possible; pin to real SDL2
(`brew install sdl2` gives compat; real SDL2 is `sdl2@2`? — verify in M0.1).
6. **`fast3d_ptr_ok` 47-bit bound** and any other `< 0x8000_0000_0000`
checks are fine at 16 TiB but would not be at ≥128 TiB — do not raise `B`
above that without checking.
## 6. Status
| Phase | State | Notes |
|---|---|---|
| Research | done | §1 F1–F18, measured 2026-09-18 |
| M0 | **superseded by #88** | the clang build/toolchain work is replaced by PR #88's GCC-based macOS layer; only D296 + `gen_macho_syms --base` survive (§0b) |
| M1 | **done** | shifted-window address model (D298); self-test ALL PASS on the #88 base |
| M2 | **in progress** | game-code re-basing sweep; boot reaches the level stage load |
| M3 | partly inherited | #88 supplies the AppKit main-thread guard; the two Core-profile GL fixes and the level sweep remain |
| M4 | not started | packaging / CI / docs |
### Prerequisites to run (easy to miss)
Two things must be in `data/` before the binary will render anything, both
documented in `docs/building.md`:
1. **The ROM** as `data/ge007.ntsc-final.z64` (SHA-1 `abe01e4a…`, matching the
repo's `ge007.u.sha1`).
2. **The PC asset sidecars** — `data/pcmodels-ntsc-final/` and
`data/pccg-ntsc-final/`. These are ROM-derived and **gitignored**, so a
fresh clone has empty directories and the game will look like it has an
address bug when it is really serving raw big-endian ROM bytes (that is
finding **D69** reproducing). Generate them once:
```sh
python3 tools_pc/d43_emit.py ntsc-final # 512 model sidecars
python3 tools_pc/d69_emit.py ntsc-final # 25 bg + 27 stan
python3 tools_pc/d88_emit.py ntsc-final --regen # + 21 stage-setup
```
This cost a detour during M2: the `bg.c` big-endian-header crash looked like
an un-rebased pointer but was the missing sidecars. PR #88's author ran the
same three passes before their 1,500-frame `-level_09` run.
### Where the boot is (2026-09-18, branch `macos-arm64-gcc`)
`./build-pc/ge007.aarch64 -level_09`, ROM `data/ge007.ntsc-final.z64`
(SHA-1 `abe01e4a…`, matching the repo's `ge007.u.sha1`):
- ROM load, config, EEPROM, GL 4.1 core, audio, input, threads, VI, timers — OK
- language banks, animation tables, `texReset`/`texLoad`, `gimgSync…` — OK
- faults in `bg.c` `load_bg_file` (level geometry) — the next M2 site
M2 batches so far (all `#if defined(PORT)` and identity at
`PORT_ADDR_BASE == 0`): the mempool boundary; `language.c` `g_LangBanks`;
`initanitable.c` `expand_ani_table_entries`; `initactorpropstuff.c` anim
groups / `ANIM_PTR`; `model.c` `bitDescriptors`/`bitStream`; `image_bank.c`
`globalbank_rdram_offset` (structural, ~43 sites at once) + `texSetBitstring`;
`image.c` `texLoadFromDisplayList`; `bg.c` `BG_SEG_TO_PTR`/`ptr_bg_data`
(**under review** — the fold's value depends on the stack address, which
differs between Windows and the macOS window, so it needs a careful look).
### The M2 census is a checklist, not a scoreboard
The clang census is ~474 game-code rows (`-Wint-conversion` 253,
`-Wpointer-to-int-cast` 122, `-Wint-to-pointer-cast` 54,
`-Wint-to-void-pointer-cast` 35, `-Wvoid-pointer-to-int-cast` 10). Re-basing
edits *add* explicit `u32 → pointer` conversions, so the raw count can rise
while progress is made, and one structural fix can clear dozens of rows. The
honest progress metric is boot-path reach.
### Next
1. Finish the `bg.c` level-geometry re-basing (the current fault), then keep
triaging `-level_09` until a frame renders.
2. Refresh §1/§3 for the #88/GCC base (the M0 rows elsewhere in this doc are
historical).
3. M3: the two Core-profile GL bugs (`gfx_opengl.cpp:1271` binds the FBO
index instead of `.fbo`; `glReadBuffer(GL_FRONT)`), the MSAA clamp, then
the level sweep and the arm64 float→int / memory-ordering checks.
+33 -25
View File
@@ -27,6 +27,7 @@
#include "gbiex.h" /* GE's G_TRI4 + PD extension opcodes (see header) */
#include "platform.h"
#include "port_addr.h"
#include "gfx_pc.h"
#include "gfx_cc.h"
@@ -687,7 +688,9 @@ void gfx_texture_cache_delete_range(const uint8_t* start, const uint8_t* end) {
// texels (0xED0F...) decode from the swapped pairs (0x4FCC/0xCC4F) as bright
// green/pink — the garbled Rareware-logo pixels.
static bool gfx_tex_source_is_c_array(const uint8_t* addr) {
const uintptr_t a = (uintptr_t)addr;
// Ranges are N64-space, so strip the window base first (identity at
// PORT_ADDR_BASE==0, where the ranges are the raw addresses).
const uintptr_t a = (uintptr_t)addr - (uintptr_t)PORT_ADDR_BASE;
if (a >= 0x10000000u && a < 0x20000000u) return false; // cart map + sidecar
if (a >= 0x70000000u && a < 0x90000000u) return false; // V1 dram + KSEG0 mirror
return true; // exe image: C-compiled array
@@ -3154,11 +3157,20 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
rsp.fog_mul = (int16_t)(data >> 16);
rsp.fog_offset = (int16_t)data;
break;
case G_MW_SEGMENT:
case G_MW_SEGMENT: {
// GE registers segment bases as OS_K0_TO_PHYSICAL(ptr); store the
// live host pointer so seg_addr() resolves seg+offset correctly.
segmentPointers[(offset >> 2) & 0xff] = (data < 0x800000) ? (data + 0x80000000) : data;
// Values that fit in 32 bits are N64-space (a small physical
// offset, or a V1 address); full 64-bit values are already host
// pointers. Identity at PORT_ADDR_BASE==0.
uintptr_t v = (uintptr_t)data;
if (v < 0x100000000ULL) {
if (v < 0x800000) v += 0x80000000u;
v = (uintptr_t)portN64ToHost((u32)v);
}
segmentPointers[(offset >> 2) & 0xff] = v;
break;
}
}
}
@@ -3799,6 +3811,12 @@ static void gfx_sp_vertex_float(size_t n_vertices, size_t dest_index, const Port
}
static inline void *seg_addr(uintptr_t w1) {
// A full 64-bit host pointer (the gSP* macros pack full pointers into w1;
// the window base makes every real host pointer >= 4 GiB) passes through
// untouched. Only values that fit in 32 bits are N64-space addresses.
if (w1 >= 0x100000000ULL) {
return (void *)w1;
}
// GE model files reference GDLs (gSPDisplayList) and vertex arrays by raw
// VMA 0x05xxxxxx WITHOUT the LSB set; segment 5 is set per-render to the
// live host file base by the game's gSPSegment. Resolve it explicitly
@@ -3828,30 +3846,20 @@ static inline void *seg_addr(uintptr_t w1) {
return (void *)(segmentPointers[seg] + (w1 & 0x00FFFFFF));
}
}
// GE passes OS_K0_TO_PHYSICAL(ptr) == ptr - 0x80000000 for RAM that lives
// in the reserved N64-DRAM region (port/src/dram.c); map it back. The
// region is 8 MB, so any offset below 0x800000 came from there.
// GE passes OS_K0_TO_PHYSICAL(ptr) == ptr - V1 base for RAM that lives in
// the reserved N64-DRAM region (port/src/dram.c); map it back into the V2
// view. The region is 8 MB, so any offset below 0x800000 came from there.
if (w1 < 0x800000) {
return (void *)(w1 + 0x80000000);
return portN64ToHost((u32)(w1 + 0x80000000));
}
// D131: a GBI DL built by game code can reference a COMPILED symbol via
// osVirtualToPhysical() (a u32-returning shim), which truncates the
// module's 0x1_00000000 high word. Seen in explosionRenderPropSmoke:
// gSPMatrix(gdl++, osVirtualToPhysical((void*)&dword_CODE_bss_8007A100),
// ..MODELVIEW) -> w1 == 0x40xxxxxx -> wild deref in gfx_sp_matrix. The
// module is based at 0x140000000 (fixed, no ASLR), and nothing legit
// reaches this fallthrough with a value in [0x40000000, DRAM_V1): DRAM
// (>=0x70000000), KSEG0 (>=0x80000000), segmented addrs and sub-0x800000
// physical offsets are all handled above. Restore the high word from
// this TU's own load address.
{
static const uintptr_t mod_hi =
((uintptr_t)(void *)&segmentPointers[0]) & 0xffffffff00000000ULL;
if (mod_hi && w1 >= 0x40000000 && w1 < 0x70000000) {
return (void *)(mod_hi | w1);
}
}
return (void *)w1;
// Everything else is a 32-bit N64-space address: DRAM V1 (0x70xxxxxx),
// KSEG0 (0x80xxxxxx), cart (0x10xxxxxx), or the image-relative encoding
// 0x40000000 + (ptr - image base) produced by osVirtualToPhysical() on a
// pointer into the executable (D131). portN64ToHost applies the window
// base and, for the image-relative range, the image base. On Windows the
// image base is 0x140000000, so this reproduces the old mod_hi|w1 exactly;
// at PORT_ADDR_BASE==0 the whole thing is the identity it was before.
return portN64ToHost((u32)w1);
}
uintptr_t clearMtx;
+2 -2
View File
@@ -42,7 +42,7 @@
#undef strncpy
#endif
#if defined(PORT) && defined(__x86_64__) && !defined(__cplusplus)
#if defined(PORT) && defined(PLATFORM_64BIT) && !defined(__cplusplus)
#include <PR/ultratypes.h> /* u8..s32, f32, size_t (host on PC) */
#include <PR/gbi.h> /* Gfx, Mtx, Vtx, Light (shimmed on PC) */
@@ -493,5 +493,5 @@ Gfx * watchRenderControllerOpaque();
u32 weaponLoadProjectileModels();
void zbufSetBuffer();
#endif /* PORT && __x86_64__ && !__cplusplus */
#endif /* PORT && PLATFORM_64BIT && !__cplusplus */
#endif /* _PC_PROTOS_H_ */
+105
View File
@@ -0,0 +1,105 @@
#ifndef PORT_ADDR_H
#define PORT_ADDR_H
/*
* The N64 address-space window (M1 of the macOS port).
*
* The port realises the N64's 32-bit address space as a range of *host*
* addresses, because the game stores addresses in 32-bit fields and 32-bit
* arithmetic and expects `(u32)ptr` to round-trip:
*
* 0x00000000..0x0fffffff segmented DL addresses (never host memory)
* 0x10000000..0x1fffffff cart image + sidecars (CART_BASE)
* 0x40000000..0x6fffffff image-relative encoding (see below)
* 0x70000000..0x707fffff DRAM V1 ("virtual", s32-safe; all RAM symbols)
* 0x80000000..0x807fffff DRAM V2 (KSEG0 mirror of V1)
* 0xa0000000..0xbfffffff game-thread stacks
*
* On Windows/Linux that range starts at host address 0, so `(u32)ptr ==
* offset` and the pointer IS the N64 address. Native arm64 macOS cannot map
* below 4 GiB (__PAGEZONE; see docs/dev/MACOS-ARM64-PLAN.md §1), so there the
* whole range is shifted up by PORT_ADDR_BASE. Every game-visible 32-bit value
* is then IDENTICAL to the Windows build; only the u32->host-pointer direction
* adds the base. PORT_ADDR_BASE is 0 everywhere but macOS, so those builds are
* unchanged.
*
* Image-relative encoding: pointers into the executable image cannot be
* truncated into the window (the image is not inside it, and on arm64 it is
* PIE with a per-run slide). They are encoded as 0x40000000 + (ptr - image
* base). On Windows the image base is 0x140000000, so this equals the raw
* `(u32)ptr` truncation the D131 fix relied on; on macOS it makes the round
* trip explicit. Ported game code must use portN64ToHost/portHostToN64 (or
* PORT_N64PTR) rather than a bare cast wherever a 32-bit field carries a
* pointer that is not a plain N64 address.
*/
#include <stdint.h>
#include "platform.h"
#if defined(PLATFORM_MACOS) && defined(PLATFORM_ARM)
/* 16 TiB: reserved cleanly on Apple Silicon, far above libmalloc's regions and
* the mmap hint area, and well below fast3d_ptr_ok()'s 128 TiB bound. The
* committed port/src/*.darwin.s files are generated with the SAME base
* (scripts/gen_romassets.py --darwin --base 0x100000000000); portAddrInit()
* checks the two agree at startup. */
#define PORT_ADDR_BASE 0x100000000000ULL
#else
#define PORT_ADDR_BASE 0x0ULL
#endif
/* Size of the N64 address space. */
#define PORT_ADDR_WINDOW (1ULL << 32)
/* Bound on the executable image's size, for classifying a host pointer as
* image-relative. The binary is a few MB; 256 MiB is comfortably generous. */
#define PORT_IMAGE_MAX (256u << 20)
/* Set by portAddrInit(): the executable's load address, and whether the image
* lies outside the window (so a truncated pointer needs the 0x40000000
* encoding). False on Linux, true on Windows and macOS. */
#ifdef __cplusplus
extern "C" {
#endif
extern uintptr_t g_portImageBase;
extern int g_portUseImageRel;
/* Reserve the window (macOS only) and record the image base. Must run before
* any of the port's fixed mappings and before large allocations. */
void portAddrInit(void);
#ifdef __cplusplus
}
#endif
/* u32 N64/physical address -> live host pointer. */
static inline void *portN64ToHost(uint32_t a)
{
if (g_portUseImageRel && a >= 0x40000000u && a < 0x70000000u) {
return (void *)(g_portImageBase + (uintptr_t)(a - 0x40000000u));
}
return (void *)((uintptr_t)PORT_ADDR_BASE + (uintptr_t)a);
}
/* Host pointer -> u32, the inverse of portN64ToHost for in-window and image
* pointers. Out-of-range pointers fall back to raw truncation (the pre-M1
* behaviour); they should not be stored in 32-bit fields. */
static inline uint32_t portHostToN64(const void *p)
{
uintptr_t v = (uintptr_t)p;
if (v - (uintptr_t)PORT_ADDR_BASE < (uintptr_t)PORT_ADDR_WINDOW) {
return (uint32_t)(v - (uintptr_t)PORT_ADDR_BASE);
}
if (g_portUseImageRel && v >= g_portImageBase
&& v - g_portImageBase < (uintptr_t)PORT_IMAGE_MAX) {
return (uint32_t)(0x40000000u + (v - g_portImageBase));
}
return (uint32_t)v;
}
/* Cast-site helper for game code (the D3x ABI/layout class): reads a 32-bit
* address out of a field/expression and yields a typed pointer. Identity on
* Windows/Linux (PORT_ADDR_BASE == 0). */
#define PORT_N64PTR(T, expr) ((T *)portN64ToHost((uint32_t)(expr)))
#endif /* PORT_ADDR_H */
+9 -1
View File
@@ -41,11 +41,19 @@
# pragma pop_macro("sprintf")
# pragma pop_macro("errno")
# endif
# include "port_addr.h" /* PORT_ADDR_BASE for the V1-base subtractions */
# undef OS_K0_TO_PHYSICAL
# define OS_K0_TO_PHYSICAL(x) ((u32)((char *)(x) - 0x70000000))
/* Offset of a DRAM V1 pointer from the V1 base. On macOS the V1 base is
* PORT_ADDR_BASE + 0x70000000, so the base must be subtracted too; the result
* is a small (< 8 MB) offset that fits s32 and that fast3d's seg_addr()
* re-bases into the V2/KSEG0 mirror. Identity behaviour at PORT_ADDR_BASE==0. */
# define OS_K0_TO_PHYSICAL(x) ((u32)((uintptr_t)(x) - (PORT_ADDR_BASE + 0x70000000ULL)))
# undef OS_PHYSICAL_TO_K0
/* Identity: callers pass either a live V1 pointer (which is preserved with
* its full 64-bit value through the 64-bit GBI words) or a small physical
* offset (which fast3d re-bases). Both are unaffected by the window base. */
# define OS_PHYSICAL_TO_K0(x) ((void *)(x))
#else
+26
View File
@@ -318,6 +318,9 @@ static LONG __stdcall crashHandler(PEXCEPTION_POINTERS exinfo)
#include <ctype.h>
#include <dlfcn.h>
#include <sys/fcntl.h>
#if defined(PLATFORM_MACOS)
#include <mach-o/dyld.h> /* _dyld_get_image_vmaddr_slide (for atos) */
#endif
static struct sigaction prevSigAction;
@@ -363,6 +366,27 @@ static void crashStackTrace(char *msg, int sig, void *pc, ucontext_t *ucontext,
(void *)ucontext->uc_mcontext.gregs[REG_RSP],
(void *)ucontext->uc_mcontext.gregs[REG_RBP]);
}
#elif defined(PLATFORM_MACOS) && defined(PLATFORM_ARM)
/* Darwin's uc_mcontext is a POINTER to __darwin_mcontext64; the arm64
* thread state is __ss.__x[0..28], __fp, __lr, __sp, __pc. */
if (ucontext) {
CRASH_MSG("REGS: x0=%p x1=%p x2=%p x3=%p x4=%p x5=%p x6=%p x7=%p\n",
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[0],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[1],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[2],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[3],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[4],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[5],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[6],
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__x[7]);
CRASH_MSG("Pc=%p Lr=%p Sp=%p Fp=%p\n",
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__pc,
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__lr,
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__sp,
(void *)(uintptr_t)ucontext->uc_mcontext->__ss.__fp);
}
CRASH_MSG("IMAGE SLIDE: 0x%lx\n",
(unsigned long)(uintptr_t)_dyld_get_image_vmaddr_slide(0));
#endif
CRASH_MSG("PC: ");
if (pc) {
@@ -422,6 +446,8 @@ static void crashHandler(int sig, siginfo_t *siginfo, void *ctx)
pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP];
#elif defined(PLATFORM_MACOS) && defined(PLATFORM_X86_64)
pc = (void *)ucontext->uc_mcontext->__ss.__rip;
#elif defined(PLATFORM_MACOS) && defined(PLATFORM_ARM)
pc = (void *)(uintptr_t)ucontext->uc_mcontext->__ss.__pc;
#endif
}
+3 -2
View File
@@ -48,6 +48,7 @@
#include "platform.h"
#include "system.h"
#include "port_addr.h"
#if defined(PLATFORM_WINDOWS)
#include <windows.h>
@@ -60,8 +61,8 @@
#include <unistd.h>
#endif
#define DRAM_V1_BASE 0x70000000UL /* s32-safe "virtual" view */
#define DRAM_K0_BASE 0x80000000UL /* KSEG0 mirror view */
#define DRAM_V1_BASE (PORT_ADDR_BASE + 0x70000000ULL) /* s32-safe "virtual" view */
#define DRAM_K0_BASE (PORT_ADDR_BASE + 0x80000000ULL) /* KSEG0 mirror view */
#define DRAM_SIZE 0x00800000UL /* 8 MB */
void *dramReserve(void)
+44 -10
View File
@@ -44,6 +44,7 @@
#include "platform.h"
#include "system.h"
#include "port_addr.h"
#include "crash.h" /* D38: crashDumpThreads() */
#include "video.h"
#include "audio.h"
@@ -418,13 +419,40 @@ void osCreateThread(OSThread *t, OSId id, void (*entry)(void *), void *arg,
#if !defined(_WIN32)
#include <sys/mman.h>
/* The decomp aligns/compares stack-buffer pointers by truncating to u32
* (e.g. `(u32)compbuffer` in image.c texLoad) — an N64 assumption. glibc
* puts pthread stacks above 4 GiB, so those truncations corrupt. Force each
* game-thread stack into the low 2 GiB with MAP_32BIT so every such idiom
* works exactly as on the console. Windows pthread stacks are already low. */
* (e.g. `(u32)compbuffer` in image.c texLoad) — an N64 assumption. Windows
* pthread stacks are already low, so every such idiom works there.
*
* On macOS the whole N64 window is reserved PROT_NONE by portAddrInit, so each
* game-thread stack is carved from the window's stack region
* [PORT_ADDR_BASE + 0xA0000000, + 0xC0000000), leaving a PROT_NONE guard page
* below it; the stack's host address then truncates to its N64 address exactly
* as on Windows.
*
* On Linux (PORT_ADDR_BASE == 0) the window is not reserved, so keep the
* original MAP_32BIT allocation: addresses below 2 GiB truncate identically. */
#define PORT_STACK_REGION_OFF 0xA0000000ULL
#define PORT_STACK_REGION_SIZE (512ULL << 20)
#define PORT_STACK_GUARD 0x4000ULL
static uintptr_t s_stackNext = 0;
static void *portAllocLowStack(size_t sz)
{
#if defined(MAP_32BIT)
#if PORT_ADDR_BASE != 0
const uintptr_t region = (uintptr_t)PORT_ADDR_BASE + PORT_STACK_REGION_OFF;
if (s_stackNext == 0)
s_stackNext = region;
const uintptr_t base = s_stackNext + PORT_STACK_GUARD;
const uintptr_t end = base + sz;
if (end > region + PORT_STACK_REGION_SIZE)
return NULL;
void *p = mmap((void *)base, sz, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (p != (void *)base)
return NULL;
s_stackNext = end;
return p;
#elif defined(MAP_32BIT)
void *p = mmap(NULL, sz, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT
#if defined(MAP_STACK)
@@ -433,8 +461,11 @@ static void *portAllocLowStack(size_t sz)
, -1, 0);
if (p != MAP_FAILED)
return p;
#endif
return NULL;
#else
(void)sz;
return NULL;
#endif
}
#endif
@@ -911,7 +942,10 @@ static int s_d61opened = 0;
static int dramHostAddrValid(uintptr_t addr, u32 size)
{
static const uintptr_t bases[2] = { 0x70000000UL, 0x80000000UL };
static const uintptr_t bases[2] = {
(uintptr_t)PORT_ADDR_BASE + 0x70000000UL,
(uintptr_t)PORT_ADDR_BASE + 0x80000000UL,
};
for (int i = 0; i < 2; i++) {
if (addr >= bases[i] && addr + size <= bases[i] + 0x00800000UL)
return 1;
@@ -1003,7 +1037,7 @@ static void piServiceDma(s32 direction, u32 srcPA, void *dstVA, u32 size)
sysFatalError("D60: ROM-read target %p + 0x%X not host-mapped "
"(src=0x%08X)", dstVA, size, srcPA);
}
memcpy(dstVA, (const void *)(uintptr_t)srcPA, size);
memcpy(dstVA, portN64ToHost(srcPA), size);
} else {
/* OS_WRITE: the game never writes the cart (saves go to EEPROM via
* osEeprom*, shimmed separately). Log and drop. */
@@ -1542,8 +1576,8 @@ void osWritebackDCache(void *addr, int size) { (void)addr; (void)size; }
void osWritebackDCacheAll(void) { }
void osInvalICache(void *addr, int size) { (void)addr; (void)size; }
void osInvalDCache(void *addr, int size) { (void)addr; (void)size; }
u32 osVirtualToPhysical(void *va) { return (u32)(uintptr_t)va; }
void *osPhysicalToVirtual(u32 pa) { return (void *)(uintptr_t)pa; }
u32 osVirtualToPhysical(void *va) { return portHostToN64(va); }
void *osPhysicalToVirtual(u32 pa) { return portN64ToHost(pa); }
/* ------------------------------------------------------------------------ */
/* Misc */
+7
View File
@@ -23,6 +23,7 @@
#include "platform.h"
#include "system.h"
#include "port_addr.h"
#include "config.h"
#include "fs.h"
#include "romdata.h"
@@ -102,6 +103,12 @@ int main(int argc, char **argv)
GE007_ROMID, GE007_VERSION_HASH, GE007_VERSION_CODENAME,
GE007_ORIGIN_URL);
/* Reserve the N64 address-space window before anything else maps or
* allocates (macOS: 4 GiB PROT_NONE; elsewhere a no-op). Must precede
* crashInit so the reservation is in place for every later stage, and any
* failure here is reported before SDL/GL are involved. */
portAddrInit();
/* Crash handler first, so any failure below is debuggable. */
crashInit();
+9 -2
View File
@@ -23,6 +23,7 @@
#include <PR/ultratypes.h>
#include <PR/os.h>
#include <tlb_manage.h>
#include "port_addr.h"
/* --- Segment start/end getters (normally linker-script symbols) --------- */
/* On the PC the ROM is loaded by romdata.c; these are unused. Return 0. */
@@ -102,8 +103,14 @@ u8 (*tlbmanageGetTlbAllocatedBlock(void))[TLB_BLOCK_SIZE]
* lives up there, at 0x707FFD30). Reclaim ~4 MB of it for the mempool
* area; the extra goes to MEMPOOL_STAGE (boss.c:218 gives STAGE
* everything that isn't the fixed PERMANENT bank). Stays well clear of
* animations_frame_buffer. */
return (u8 (*)[TLB_BLOCK_SIZE])0x70700000;
* animations_frame_buffer.
*
* D298 (macOS/arm64): the same reclaim is not quite enough there — the
* first level load exhausts STAGE by ~0x30 bytes at a model rwdata alloc
* (mempAllocBytesInBank spins). Push the ceiling to the last 0x10000
* before animations_frame_buffer, adding ~960 KiB to STAGE. Same
* reasoning as above; no game-logic change. */
return (u8 (*)[TLB_BLOCK_SIZE])portN64ToHost(0x707F0000);
}
/* --- K&R libc helpers (IDO provided these; MinGW's libc does not) -------- */
+110
View File
@@ -0,0 +1,110 @@
/*
* port_addr.c — the N64 address-space window (see port/include/port_addr.h).
*
* On macOS/arm64 the whole window is reserved PROT_NONE up front so that the
* fixed-address carves (cart, DRAM V1/V2, game-thread stacks, in dram.c /
* romdata.c / libultra.c) land inside a range the process already owns and
* cannot collide with libmalloc or the dyld shared cache. Reserving is cheap:
* PROT_NONE pages are not committed.
*
* On Windows/Linux PORT_ADDR_BASE is 0 and this is a no-op beyond recording
* the image base.
*/
#include <stdint.h>
#include "platform.h"
#include "system.h"
#include "port_addr.h"
#if defined(PLATFORM_MACOS) && defined(PLATFORM_ARM)
#include <mach/mach.h>
#include <mach/mach_vm.h>
#endif
uintptr_t g_portImageBase = 0;
int g_portUseImageRel = 0;
/* Defined by port/src/dram_syms*.s; must equal PORT_ADDR_BASE + 0x70000000. */
extern unsigned char cfb_16[];
/* ROM-free verification of the address model: window round-trips for each
* region, the absolute-symbol base, and the image-relative encoding. Logs
* PASS/FAIL for each so a run without a ROM still exercises the core. */
static int portAddrCheck(const char *what, int ok)
{
sysLogPrintf(ok ? LOG_INFO : LOG_ERROR, "portAddr: %-26s %s",
what, ok ? "PASS" : "FAIL");
return ok;
}
static void portAddrSelfTest(void)
{
const uintptr_t B = (uintptr_t)PORT_ADDR_BASE;
int ok = 1;
ok &= portAddrCheck("host->n64 DRAM V1",
portHostToN64((void *)(B + 0x70001234u)) == 0x70001234u);
ok &= portAddrCheck("n64->host DRAM V1",
portN64ToHost(0x70001234u) == (void *)(B + 0x70001234u));
ok &= portAddrCheck("host->n64 DRAM V2",
portHostToN64((void *)(B + 0x80005678u)) == 0x80005678u);
ok &= portAddrCheck("host->n64 cart",
portHostToN64((void *)(B + 0x10456789u)) == 0x10456789u);
ok &= portAddrCheck("n64->host cart",
portN64ToHost(0x10456789u) == (void *)(B + 0x10456789u));
ok &= portAddrCheck("cfb_16 at base+DRAM_V1",
(uintptr_t)cfb_16 == B + 0x70000000u);
if (g_portUseImageRel) {
ok &= portAddrCheck("host->n64 image",
portHostToN64((void *)(g_portImageBase + 0x1234u)) == 0x40001234u);
ok &= portAddrCheck("n64->host image",
portN64ToHost(0x40001234u) == (void *)(g_portImageBase + 0x1234u));
}
sysLogPrintf(ok ? LOG_INFO : LOG_ERROR, "portAddr: selftest %s",
ok ? "ALL PASS" : "FAILURES");
}
void portAddrInit(void)
{
g_portImageBase = sysImageBase();
/* The image needs the 0x40000000 encoding iff it lies outside the window,
* i.e. its address does not survive a u32 truncation. False on Linux
* (image at 0x20000000, inside the window), true on Windows (0x140000000)
* and macOS (0x1_00xxxxxx + slide). */
g_portUseImageRel = (g_portImageBase >= (uintptr_t)PORT_ADDR_WINDOW) ? 1 : 0;
#if PORT_ADDR_BASE != 0
{
/* Non-clobbering: VM_FLAGS_FIXED without VM_FLAGS_OVERWRITE fails with
* KERN_NO_SPACE if the range is already in use, rather than silently
* replacing a live mapping (mmap MAP_FIXED on macOS does the latter). */
mach_vm_address_t addr = (mach_vm_address_t)PORT_ADDR_BASE;
kern_return_t kr = mach_vm_map(mach_task_self(), &addr,
(mach_vm_size_t)PORT_ADDR_WINDOW, 0,
VM_FLAGS_FIXED, MEMORY_OBJECT_NULL, 0, FALSE,
VM_PROT_NONE, VM_PROT_ALL, VM_INHERIT_DEFAULT);
if (kr != KERN_SUCCESS || addr != (mach_vm_address_t)PORT_ADDR_BASE) {
sysFatalError("portAddr: cannot reserve the 4 GiB N64 window at "
"0x%llx (%s). See docs/dev/MACOS-ARM64-PLAN.md sec 2.",
(unsigned long long)PORT_ADDR_BASE, mach_error_string(kr));
}
}
#endif
/* The committed .darwin.s absolute symbols must have been generated with
* the same --base; cfb_16 is a region-independent sentinel for that. */
if ((uintptr_t)cfb_16 != (uintptr_t)PORT_ADDR_BASE + 0x70000000ULL) {
sysFatalError("portAddr: dram_syms base mismatch (cfb_16=%p, expected 0x%llx). "
"Regenerate with: scripts/gen_romassets.py <region> --darwin "
"--base 0x%llx --rom-size <size> --out ... --dram-out ...",
(void *)cfb_16,
(unsigned long long)((uintptr_t)PORT_ADDR_BASE + 0x70000000ULL),
(unsigned long long)PORT_ADDR_BASE);
}
sysLogPrintf(LOG_INFO, "portAddr: window base=0x%llx image=0x%llx image_rel=%d",
(unsigned long long)PORT_ADDR_BASE,
(unsigned long long)g_portImageBase, g_portUseImageRel);
portAddrSelfTest();
}
+22 -12
View File
@@ -45,6 +45,7 @@ extern int snprintf(char *str, size_t maxsize, const char *format, ...);
#include "pcmodels.h"
#include "pccg.h"
#include "romconvert.h"
#include "port_addr.h"
/* D50: struct font/fontchar layouts for the font-segment re-layout. Order
* matters (see pcmodels.c): ultra64.h must finish before bondtypes.h. */
@@ -60,7 +61,11 @@ extern int snprintf(char *str, size_t maxsize, const char *format, ...);
#include <errno.h>
#endif
#define CART_BASE 0x10000000u
#define CART_BASE 0x10000000u /* N64 cart address */
/* Host address the ROM is mapped at (PORT_ADDR_BASE + CART_BASE; identity on
* Windows/Linux). Game-visible 32-bit cart values stay CART_BASE-based; this
* is only for the mapping and the host-side pointers into it. */
#define CART_HOST ((uintptr_t)portN64ToHost(CART_BASE))
static u8 *rom = NULL; /* heap copy (fallback path) */
static u32 romSize = 0;
@@ -240,15 +245,15 @@ static void romdataRaw16Walk(const u8 *ctl, u32 ctlSize, u8 *tbl, u32 tblSize,
static int romdataFinishCartMap(const char *tok, u8 *img,
u32 sideTotal, u32 cgTotal)
{
memcpy((void *)(uintptr_t)CART_BASE, img, romSize);
memcpy((void *)CART_HOST, img, romSize);
free(img);
mappedAtCartBase = 1;
sysLogPrintf(LOG_INFO, "romdataInit: %s (%u bytes) mapped at 0x%08X "
"(cart base)%s%s", tok, romSize, CART_BASE,
sideTotal ? ", + model sidecars" : "",
cgTotal ? ", + bg/stan sidecars" : "");
pcmodelsLoadSidecars(CART_BASE, romSize);
pccgLoadSidecars(CART_BASE + romSize + pcmodelsTotalSize());
pcmodelsLoadSidecars(CART_HOST, romSize);
pccgLoadSidecars(CART_HOST + romSize + pcmodelsTotalSize());
/* D55: the RLE folder-menu background at `unknown2` has a big-endian w/h
* header that rle_expand_8bit() reads little-endian; match the N64 .data
@@ -374,9 +379,9 @@ int romdataInit(void)
{
u32 maplen = romSize + sideTotal + cgTotal;
#if defined(PLATFORM_WINDOWS)
void *at = VirtualAlloc((LPVOID)CART_BASE, maplen,
void *at = VirtualAlloc((LPVOID)CART_HOST, maplen,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (at == (void *)(uintptr_t)CART_BASE)
if (at == (void *)CART_HOST)
return romdataFinishCartMap(tok, img, sideTotal, cgTotal);
if (at)
VirtualFree(at, 0, MEM_RELEASE);
@@ -387,8 +392,10 @@ int romdataInit(void)
/* POSIX: anonymous fixed-address mmap. MAP_FIXED_NOREPLACE (Linux
* 4.17+) fails instead of clobbering an existing mapping; where it
* is unavailable the plain hint is advisory and the == check below
* catches a relocated result. */
* catches a relocated result. On macOS portAddrInit has already
* reserved the whole window, so MAP_FIXED lands inside our range. */
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
#ifndef PLATFORM_MACOS
#ifdef MAP_FIXED_NOREPLACE
flags |= MAP_FIXED_NOREPLACE;
#elif defined(PLATFORM_MACOS)
@@ -397,10 +404,13 @@ int romdataInit(void)
* otherwise treats CART_BASE only as a hint, relocating it. */
flags |= MAP_FIXED;
#endif
void *at = mmap((void *)(uintptr_t)CART_BASE, maplen,
#else
flags |= MAP_FIXED;
#endif
void *at = mmap((void *)CART_HOST, maplen,
PROT_READ | PROT_WRITE, flags, -1, 0);
int mapErrno = errno;
if (at != MAP_FAILED && at == (void *)(uintptr_t)CART_BASE) {
if (at != MAP_FAILED && at == (void *)CART_HOST) {
mappedLen = maplen;
return romdataFinishCartMap(tok, img, sideTotal, cgTotal);
}
@@ -425,9 +435,9 @@ void romdataDestroy(void)
{
if (mappedAtCartBase) {
#if defined(PLATFORM_WINDOWS)
VirtualFree((LPVOID)CART_BASE, 0, MEM_RELEASE);
VirtualFree((LPVOID)CART_HOST, 0, MEM_RELEASE);
#else
munmap((void *)(uintptr_t)CART_BASE, (size_t)mappedLen);
munmap((void *)CART_HOST, (size_t)mappedLen);
mappedLen = 0;
#endif
mappedAtCartBase = 0;
@@ -440,7 +450,7 @@ void romdataDestroy(void)
const u8 *romdataGetRom(void)
{
if (mappedAtCartBase)
return (const u8 *)(uintptr_t)CART_BASE;
return (const u8 *)CART_HOST;
return rom;
}
u32 romdataGetRomSize(void) { return romSize; }
+45 -10
View File
@@ -27,6 +27,9 @@
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#if defined(PLATFORM_MACOS)
#include <mach-o/dyld.h> /* _dyld_get_image_header, _NSGetExecutablePath */
#endif
#endif
#include "system.h"
@@ -59,12 +62,46 @@ uintptr_t sysImageBase(void)
{
#if defined(PLATFORM_WINDOWS)
return (uintptr_t)GetModuleHandleW(NULL);
#elif defined(PLATFORM_MACOS)
/* The mach_header of the main image == its load address. Unlike Windows
* there is no fixed base: arm64 is PIE-only (and `-image_base` is ignored),
* so this is 0x1_0000_0000 + a per-run ASLR slide. M1's image-relative
* address rule uses this; get the slide from _dyld_get_image_vmaddr_slide. */
return (uintptr_t)_dyld_get_image_header(0);
#else
/* TODO: parse /proc/self/maps for the first executable mapping. */
return 0;
#endif
}
/* Fill `buf` with the directory containing the executable, or "" on failure.
* Linux reads /proc/self/exe; macOS uses _NSGetExecutablePath (no /proc, and
* _POSIX_C_SOURCE=199309L above hides readlink on Darwin). */
static void getExeDir(char *buf, size_t buflen)
{
buf[0] = 0;
#if defined(PLATFORM_MACOS)
uint32_t n = (uint32_t)buflen;
if (_NSGetExecutablePath(buf, &n) == 0) {
char *slash = strrchr(buf, '/');
if (slash) *slash = 0; else buf[0] = 0;
} else {
buf[0] = 0;
}
#elif defined(PLATFORM_LINUX)
ssize_t n = readlink("/proc/self/exe", buf, buflen - 1);
if (n > 0) {
buf[n] = 0;
char *slash = strrchr(buf, '/');
if (slash) *slash = 0; else buf[0] = 0;
} else {
buf[0] = 0;
}
#else
(void)buf; (void)buflen;
#endif
}
int64_t sysGetTime(void)
{
return (int64_t)time(NULL);
@@ -201,6 +238,13 @@ const char *sysGetExeDir(void)
*slash = 0;
}
}
#else
if (exeDir[0] == '.' && exeDir[1] == 0) {
char d[512];
getExeDir(d, sizeof(d));
if (d[0])
snprintf(exeDir, sizeof(exeDir), "%s", d);
}
#endif
return exeDir;
}
@@ -257,16 +301,7 @@ const char *sysResolvePath(const char *path)
else {
static char sexedir[1024] = "";
if (!sexedir[0]) {
ssize_t n = readlink("/proc/self/exe", sexedir, sizeof(sexedir) - 1);
if (n > 0) {
char *slash;
sexedir[n] = 0;
slash = strrchr(sexedir, '/');
if (slash)
*slash = 0;
else
sexedir[0] = 0;
}
getExeDir(sexedir, sizeof(sexedir));
}
if (sexedir[0])
snprintf(out, sizeof(out), "%s/data/%s", sexedir, path + 3);
+25 -7
View File
@@ -1,18 +1,33 @@
#!/usr/bin/env python3
"""Convert ELF/PE GAS absolute symbols to Mach-O spelling."""
"""Convert ELF/PE GAS absolute symbols to Mach-O spelling.
Darwin needs `.data` (not `.section .data`), `_`-prefixed symbol names, and
`.globl` (not `.global`). The cross-platform source files in port/src/ are left
untouched; the Mach-O spelling is generated into the build tree.
--base is the Apple Silicon extension: PORT_ADDR_BASE, the host address the
whole N64 address space is shifted to (see port/include/port_addr.h). It is
added to every absolute value, so `cfb_16` becomes PORT_ADDR_BASE + 0x70000000.
With --base 0 (Intel) the output is byte-identical to the original transform.
"""
import argparse
import pathlib
import re
import sys
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} INPUT OUTPUT", file=sys.stderr)
return 2
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("input")
ap.add_argument("output")
ap.add_argument("--base", type=lambda s: int(s, 0), default=0,
help="host address of the N64 address space "
"(PORT_ADDR_BASE; default 0)")
args = ap.parse_args()
source = pathlib.Path(sys.argv[1])
output = pathlib.Path(sys.argv[2])
source = pathlib.Path(args.input)
output = pathlib.Path(args.output)
lines = []
for line in source.read_text(encoding="utf-8").splitlines():
@@ -25,11 +40,14 @@ def main() -> int:
continue
match = re.match(
r"^(\s*)\.set\s+([A-Za-z_]\w*)(\s*,.*)$", line
r"^(\s*)\.set\s+([A-Za-z_]\w*)(\s*,\s*)(0[xX][0-9A-Fa-f]+|\d+)(.*)$",
line,
)
if match:
value = int(match.group(4), 0) + args.base
lines.append(
f"{match.group(1)}.set _{match.group(2)}{match.group(3)}"
f"0x{value:X}{match.group(5)}"
)
continue
+3 -3
View File
@@ -7,7 +7,7 @@
#include "speed_graph.h"
#if defined(PORT)
#include <string.h> /* PC port: memcpy for the CUSTOM_FX_PARAMS_N copy in audioInit (docs/dev/findings.md §11) */
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#include <stdio.h>
#include <stdlib.h>
#ifdef PORT
@@ -666,7 +666,7 @@ s32 amDmaCallback(s32 addr, s32 len, void* state)
/* mark it used */
dmaPtr->lastFrame = (s32) g_AudioFrameCount;
freeBuffer = (dmaPtr->ptr + addr) - dmaPtr->startAddr;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
if (GE_ENVFLAG("GE_MIXERTRACE")) {
static FILE *dtf2 = NULL;
if (!dtf2) { dtf2 = fopen("mixertrace.log", "a"); if (dtf2) setvbuf(dtf2, NULL, _IONBF, 0); }
@@ -734,7 +734,7 @@ s32 amDmaCallback(s32 addr, s32 len, void* state)
dmaPtr->lastFrame = g_AudioFrameCount;
osPiStartDma(&g_DmaIOMessageBuffer[g_NextDMa++], OS_MESG_PRI_HIGH, OS_READ, (u32)addr, freeBuffer, AUDIO_DMA_MAX_BUFFER_LENGTH, &g_DmaMessageQueue);
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
if (GE_ENVFLAG("GE_MIXERTRACE")) {
static FILE *dtf3 = NULL;
if (!dtf3) { dtf3 = fopen("mixertrace.log", "a"); if (dtf3) setvbuf(dtf3, NULL, _IONBF, 0); }
+1 -1
View File
@@ -833,7 +833,7 @@ void bossMainloop(void)
}
rspReplyMsg = (s32)(&localGfxDoneMsg);
rspGfxTaskStart(firstGdl, gdl, 0, (s32*)rspReplyMsg);
rspGfxTaskStart(firstGdl, gdl, 0, PORT_N64PTR(s32, rspReplyMsg));
pendingGfx++;
memaSingleDefragPass();
+23 -17
View File
@@ -7,6 +7,12 @@
#include <fr.h>
#include <memp.h>
#include "bg.h"
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include "bondview.h"
#include "chr.h"
#include "debug_camera.h"
@@ -879,22 +885,22 @@ void load_bg_file(LEVEL_INDEX levelid)
lightFixtureInitTables();
ptr_bg_data = (s32)header;
obLoadBGFileBytesAtOffset(levelinfotable[levelentry_index].bg_seg_filename, (u8 *) ptr_bg_data, 0, 0x40);
obLoadBGFileBytesAtOffset(levelinfotable[levelentry_index].bg_seg_filename, (u8 *)PORT_N64PTR(void, ptr_bg_data), 0, 0x40);
if (((levelid && ptr_bg_data) && levelentry_index));
ptr_bgdata_offsets = ptr_bg_data;
ptr_bgdata_room_fileposition_list = (bg_room_data *) BG_SEG_TO_PTR(ptr_bg_data, ((s32 *)ptr_bg_data)[1]);
ptr_bgdata_room_fileposition_list = (bg_room_data *) BG_SEG_TO_PTR(ptr_bg_data, ((s32 *)PORT_N64PTR(void, ptr_bg_data))[1]);
size = (((((u32) ptr_bgdata_room_fileposition_list[1].pPointTableBin) & 0x00ffffff) - 1) | 0xf) + 1;
ptr_bg_data = (s32) mempAllocBytesInBank(size, 4);
obLoadBGFileBytesAtOffset(levelinfotable[levelentry_index].bg_seg_filename, (u8 *) ptr_bg_data, 0, size);
obLoadBGFileBytesAtOffset(levelinfotable[levelentry_index].bg_seg_filename, (u8 *)PORT_N64PTR(void, ptr_bg_data), 0, size);
gptr_stan = (s32) _fileNameLoadToBank(levelinfotable[levelentry_index].bg_stan_filename, 2, 0, 4);
stanDetermineEOF((struct StanPrefixRecord *) gptr_stan, 0, (u8 *) gptr_stan);
stanLoadFile((struct StanPrefixRecord *) gptr_stan);
stanDetermineEOF((struct StanPrefixRecord *)PORT_N64PTR(void, gptr_stan), 0, (u8 *)PORT_N64PTR(void, gptr_stan));
stanLoadFile((struct StanPrefixRecord *)PORT_N64PTR(void, gptr_stan));
sub_GAME_7F0B4810(levelinfotable[levelentry_index].levelscale);
setLevelScale(levelinfotable[levelentry_index].levelscale);
@@ -906,7 +912,7 @@ void load_bg_file(LEVEL_INDEX levelid)
sub_GAME_7F08976C(mCurrentLevelVisibilityScale);
matrix_4x4_7F058C4C(mCurrentLevelVisibilityScale);
data = (s32 *)ptr_bg_data;
data = (s32 *)PORT_N64PTR(void, ptr_bg_data);
dword_CODE_bss_8007BF98 = *data;
dword_CODE_bss_8007FF88 = 1;
@@ -914,7 +920,7 @@ void load_bg_file(LEVEL_INDEX levelid)
{
dword_CODE_bss_8007FF88 = 2;
ptr_bgdata_offsets = (s32)data;
ptr_bgdata_room_fileposition_list = (bg_room_data *) BG_SEG_TO_PTR(data, ((s32 *)ptr_bgdata_offsets)[1]);
ptr_bgdata_room_fileposition_list = (bg_room_data *) BG_SEG_TO_PTR(data, ((s32 *)PORT_N64PTR(void, ptr_bgdata_offsets))[1]);
// Keep this fake goto for matching.
goto dummy_label_543534; dummy_label_543534: ;
@@ -926,25 +932,25 @@ void load_bg_file(LEVEL_INDEX levelid)
g_MaxNumRooms++;
}
g_BgPortals = (bg_portal_data_entry *) BG_SEG_TO_PTR(data, ((s32 *)ptr_bgdata_offsets)[2]);
g_BgPortals = (bg_portal_data_entry *) BG_SEG_TO_PTR(data, ((s32 *)PORT_N64PTR(void, ptr_bgdata_offsets))[2]);
if (1);
if (((s32 *)ptr_bgdata_offsets)[3] == 0)
if (((s32 *)PORT_N64PTR(void, ptr_bgdata_offsets))[3] == 0)
{
dword_CODE_bss_8007FF90 = 0;
}
else
{
dword_CODE_bss_8007FF90 = (s32 *) BG_SEG_TO_PTR(data, ((s32 *)ptr_bgdata_offsets)[3]);
dword_CODE_bss_8007FF90 = (s32 *) BG_SEG_TO_PTR(data, ((s32 *)PORT_N64PTR(void, ptr_bgdata_offsets))[3]);
if (((s32 *)ptr_bgdata_offsets)[4] == 0)
if (((s32 *)PORT_N64PTR(void, ptr_bgdata_offsets))[4] == 0)
{
dword_CODE_bss_8007FF94 = NULL;
}
else
{
dword_CODE_bss_8007FF94 = (f32 *) BG_SEG_TO_PTR(data, ((s32 *)ptr_bgdata_offsets)[4]);
dword_CODE_bss_8007FF94 = (f32 *) BG_SEG_TO_PTR(data, ((s32 *)PORT_N64PTR(void, ptr_bgdata_offsets))[4]);
}
}
@@ -3149,7 +3155,7 @@ void bgBuildRoomVtxBounds(s32 roomID)
numvertices = ((gdl[cmdindex].dma.par >> 4) & 0xf) + 1;
#endif
vtx = (Vtx *)(SEGMENT_OFFSET(gdl[cmdindex].dma.addr) + (u32)vertices);
vtx = (Vtx *)PORT_N64PTR(void, SEGMENT_OFFSET(gdl[cmdindex].dma.addr) + (u32)vertices);
#if defined(PORT)
/* TEMP D69 safety net: the room primary/secondary DL binaries
@@ -3573,7 +3579,7 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV
if (bgTestRayIntersectsBbox(from, dir, (s32 *) (&bboxMin), (s32 *) (&bboxMax)))
{
if (intersectRayTriangle((Vertex *)((s32)vtxbase - (0 - (idx[0] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx[1] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx[2] << 4))), (coord3d *) (((roomnum * 24) + ((s32) ptr_bgdata_room_fileposition_list)) + 12), from, to, dir, &hitbuf))
if (intersectRayTriangle((Vertex *)((s32)vtxbase - (0 - (idx[0] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx[1] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx[2] << 4))), (coord3d *) (((roomnum * 24) + ((uintptr_t) ptr_bgdata_room_fileposition_list)) + 12), from, to, dir, &hitbuf))
{
tcmd = gdl;
dx = ((s32) hitbuf.hitpos.x) - ((s32) from->x);
@@ -3758,7 +3764,7 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV
if (bgTestRayIntersectsBbox(from, dir, (s32 *) (&bboxMin2), (s32 *) (&bboxMax2)))
{
if (intersectRayTriangle((Vertex *)((s32)vtxbase - (0 - (idx2[0] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx2[1] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx2[2] << 4))), (coord3d *) (((roomnum * 24) + ((s32) ptr_bgdata_room_fileposition_list)) + 12), from, to, dir, &hitbuf))
if (intersectRayTriangle((Vertex *)((s32)vtxbase - (0 - (idx2[0] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx2[1] << 4))), (Vertex *)((s32)vtxbase - (0 - (idx2[2] << 4))), (coord3d *) (((roomnum * 24) + ((uintptr_t) ptr_bgdata_room_fileposition_list)) + 12), from, to, dir, &hitbuf))
{
tcmd = gdl;
dx = ((s32) hitbuf.hitpos.x) - ((s32) from->x);
@@ -5241,7 +5247,7 @@ void bgRoomCalcBB(s32 room) // canonical name
StanRoomBounds limits;
u8 wasloaded;
roomdata = (bg_room_data *) ((s32) ptr_bgdata_room_fileposition_list + room * 24);
roomdata = (bg_room_data *) ((uintptr_t) ptr_bgdata_room_fileposition_list + room * 24);
if (roomdata->pPointTableBin == NULL)
{
@@ -5274,7 +5280,7 @@ void bgRoomCalcBB(s32 room) // canonical name
}
vertices = g_BgRoomInfo[room].vertices;
roomdata = (bg_room_data *) ((s32) ptr_bgdata_room_fileposition_list + room * 24);
roomdata = (bg_room_data *) ((uintptr_t) ptr_bgdata_room_fileposition_list + room * 24);
limits.minX = 0x7fff;
limits.minY = 0x7fff;
+8
View File
@@ -20,7 +20,15 @@ struct levelentry
// cannonical name
#define PORTMAX 200
/* D298/M2: the sum is an N64/window offset, so re-base it into the DRAM
* window before it becomes a pointer. Identity at PORT_ADDR_BASE == 0. */
#if defined(PORT)
#include "port_addr.h"
#define BG_SEG_TO_PTR(base, off) \
((void *) portN64ToHost((u32)(((u32)(base)) + (((u32)(off)) + 0xF1000000))))
#else
#define BG_SEG_TO_PTR(base, off) ((void *) (((u32) (base)) + (((u32) (off)) + 0xF1000000)))
#endif
typedef struct RoomVtxBatchBounds {
s16 gdlindex; // 0x00
+43 -16
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#ifdef PORT
#include <stdio.h>
#include <stdlib.h>
@@ -93,8 +98,15 @@
#if defined(VERSION_US)
/* D298/M2: the font-table globals are s32 holding truncated pointers
* (D88 class); re-base on use. Identity at PORT_ADDR_BASE == 0. */
#if defined(PORT)
#define BONDVIEW_2ND_FONTTABLE(_param) PORT_N64PTR(void, copy_2ndfonttable)
#define BONDVIEW_1ST_FONTTABLE(_param) PORT_N64PTR(void, copy_1stfonttable)
#else
#define BONDVIEW_2ND_FONTTABLE(_param) copy_2ndfonttable
#define BONDVIEW_1ST_FONTTABLE(_param) copy_1stfonttable
#endif
#elif defined(VERSION_JP) || defined(VERSION_EU)
#define BONDVIEW_2ND_FONTTABLE(_param) dword_CODE_bss_jp80079CEC[_param]
#define BONDVIEW_1ST_FONTTABLE(_param) dword_CODE_bss_jp80079Cd8[_param]
@@ -723,7 +735,7 @@ void solo_char_load(void)
pitemheader = NULL;
}
something_with_generating_object(self, prop, item, 0, (WeaponObjRecord *)helddst, (ItemModelFileRecord *)pitemheader);
something_with_generating_object(self, prop, item, 0, PORT_N64PTR(WeaponObjRecord, helddst), (ItemModelFileRecord *)pitemheader);
}
chrlvMergeKneelToStand(self, 0.0f);
@@ -981,7 +993,7 @@ void bondviewSetCameraMode(s32 arg0)
solo_char_load();
// HACK: ptr_animation_table->data regalloc is backwards
sp38 = (struct ModelAnimation *)((s32)stage_intro_anim_table[g_IntroAnimationIndex].anonymous_0 + (s32)&ptr_animation_table->data);
sp38 = PORT_N64PTR(struct ModelAnimation, (s32)stage_intro_anim_table[g_IntroAnimationIndex].anonymous_0 + (s32)&ptr_animation_table->data);
sp78 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_2;
ftemp_1 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_1;
ftemp_3 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_3;
@@ -1226,7 +1238,15 @@ void bondviewCalcIntroSwirlCamera(s32 index, f32 time, coord3d *pos, coord3d *lo
{
struct SetupIntroSwirl *base;
struct SetupIntroSwirl *loopbase;
#if defined(PORT)
/* D189/D298: written pointbuf[0..11] via `&pointbuf[i*3]` then dst[3..5]
* (i = -1..2), but declared [10] -- a 2-float stack overrun that on arm64
* corrupts the saved frame pointer (Fp=0x374d56eac1a00000 at the fault).
* N64/MinGW absorb it; give it room on the port. */
f32 pointbuf[12];
#else
f32 pointbuf[10];
#endif
struct SetupIntroSwirl *swirl;
f32 frac;
f32 *dst;
@@ -1317,7 +1337,7 @@ void bondviewCalcIntroSwirlCamera(s32 index, f32 time, coord3d *pos, coord3d *lo
lookat->y = g_CurrentPlayer->field_3C8;
lookat->z = g_CurrentPlayer->field_3CC;
swirl = (void *)(((u32) g_IntroSwirl) + (u32) base);
swirl = (void *)(((uintptr_t) g_IntroSwirl) + (uintptr_t) base); /* D298/M2: full-width */
if (!(swirl->bitflags & 4))
{
@@ -1371,13 +1391,13 @@ void bondviewFrozenCameraTick(u16 buttons, u16 oldbuttons, struct coord3d *pos,
#if defined(VERSION_US)
setFontTables(ptrFontZurichBoldChars, ptrFontZurichBold);
#ifdef PORT
hudmsgBottomShow((char *)(uintptr_t)ptr_random06cam_entry->lang1c.lang_ptr);
hudmsgBottomShow(PORT_N64PTR(char, ptr_random06cam_entry->lang1c.lang_ptr));
#else
hudmsgBottomShow(ptr_random06cam_entry->lang1c.lang_ptr);
#endif
#else
#ifdef PORT
hudmsgBottomShow((char *)(uintptr_t)ptr_random06cam_entry->lang1c.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold);
hudmsgBottomShow(PORT_N64PTR(char, ptr_random06cam_entry->lang1c.lang_ptr), ptrFontZurichBoldChars, ptrFontZurichBold);
#else
hudmsgBottomShow(ptr_random06cam_entry->lang1c.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold);
#endif
@@ -1390,13 +1410,13 @@ void bondviewFrozenCameraTick(u16 buttons, u16 oldbuttons, struct coord3d *pos,
{
#if defined(VERSION_US)
#ifdef PORT
hudmsgBottomShow((char *)(uintptr_t)ptr_random06cam_entry->lang20.lang_ptr);
hudmsgBottomShow(PORT_N64PTR(char, ptr_random06cam_entry->lang20.lang_ptr));
#else
hudmsgBottomShow(ptr_random06cam_entry->lang20.lang_ptr);
#endif
#else
#ifdef PORT
hudmsgBottomShow((char *)(uintptr_t)ptr_random06cam_entry->lang20.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold);
hudmsgBottomShow(PORT_N64PTR(char, ptr_random06cam_entry->lang20.lang_ptr), ptrFontZurichBoldChars, ptrFontZurichBold);
#else
hudmsgBottomShow(ptr_random06cam_entry->lang20.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold);
#endif
@@ -7975,6 +7995,7 @@ void bondviewFrozenMoveBond(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons)
return;
}
room_pointer_tile = (struct StandTile *)0;
bondviewFrozenCameraTick(buttons, oldbuttons, &property_pos, &property_pos2, &property_offset, &room_pointer_tile, &stan_walk_start);
currentPlayerSetCameraMode(1);
bondviewSetCurrentPlayerPosition(&property_pos, &property_pos2, &property_offset, room_pointer_tile, &stan_walk_start);
@@ -8445,12 +8466,12 @@ void bondviewUpdateCameraMatrices(coord3d* cam_pos, coord3d* cam_look_dir, coord
clpos.x, clpos.y, clpos.z,
cam_up->x, cam_up->y, cam_up->z);
matrix_4x4_set_lookat((Mtxf*) g_CurrentPlayer->field_64,
matrix_4x4_set_lookat(PORT_N64PTR(Mtxf, g_CurrentPlayer->field_64),
cam_pos->x, cam_pos->y, cam_pos->z,
cam_look_dir->x, cam_look_dir->y, cam_look_dir->z,
cam_up->x, cam_up->y, cam_up->z);
matrix_4x4_set_basis_and_position((Mtxf*) g_CurrentPlayer->field_68,
matrix_4x4_set_basis_and_position(PORT_N64PTR(Mtxf, g_CurrentPlayer->field_68),
cam_pos->x, cam_pos->y, cam_pos->z,
cam_look_dir->x, cam_look_dir->y, cam_look_dir->z,
cam_up->x, cam_up->y, cam_up->z);
@@ -8481,13 +8502,13 @@ void bondviewUpdateCameraMatrices(coord3d* cam_pos, coord3d* cam_look_dir, coord
scale = bgGetLevelVisibilityScale();
matrix_scalar_multiply(scale, spC4.m[0]);
guMtxF2L((f32 (*)[4]) &spC4, (Mtx* ) g_CurrentPlayer->field_5C);
sub_GAME_7F059334((s32* ) g_CurrentPlayer->field_5C, (s32* ) g_CurrentPlayer->field_60);
guMtxF2L((f32 (*)[4]) &spC4, PORT_N64PTR(Mtx, g_CurrentPlayer->field_5C));
sub_GAME_7F059334(PORT_N64PTR(s32, g_CurrentPlayer->field_5C), PORT_N64PTR(s32, g_CurrentPlayer->field_60));
currentPlayerSetMatrix10C8((Mtx* ) g_CurrentPlayer->field_5C);
currentPlayerSetMatrix10C4((Mtx* ) g_CurrentPlayer->field_60);
currentPlayerSetMatrix10CC((Mtxf* ) g_CurrentPlayer->field_64);
currentPlayerSetViewToWorldMtxf((Mtxf* ) g_CurrentPlayer->field_68);
currentPlayerSetMatrix10C8(PORT_N64PTR(Mtx, g_CurrentPlayer->field_5C));
currentPlayerSetMatrix10C4(PORT_N64PTR(Mtx, g_CurrentPlayer->field_60));
currentPlayerSetMatrix10CC(PORT_N64PTR(Mtxf, g_CurrentPlayer->field_64));
currentPlayerSetViewToWorldMtxf(PORT_N64PTR(Mtxf, g_CurrentPlayer->field_68));
sub_GAME_7F078464((s32) lookat);
bondviewUpdateFrustumPlanes();
@@ -10380,7 +10401,13 @@ Gfx* hudmsgBottomRender(Gfx* arg0)
}
view_vert = view_top - view_top_offset;
#ifdef PORT
/* D298/M2: the (s32) casts are an N64 match hack; on the port they
* truncate stack pointers. Pass them at full width. */
arg0 = draw_blackbox_to_screen(arg0, &view_left, &view_vert, &view_horiz, &view_top);
#else
arg0 = draw_blackbox_to_screen(arg0, (s32) &view_left, (s32) &view_vert, (s32) &view_horiz, (s32) &view_top);
#endif
arg0 = combiner_bayer_lod_perspective(textRenderOutlined(arg0, &view_left, &view_vert, stringbuffer_lowerleft[status_bar_text_buffer_index], BONDVIEW_2ND_FONTTABLE(status_bar_text_buffer_index), BONDVIEW_1ST_FONTTABLE(status_bar_text_buffer_index), -1, 0x646464FFU, (s16) (s32) viGetX(), (s16) viGetY(), 0, 0));
}
}
@@ -11393,7 +11420,7 @@ void sub_GAME_7F08BEEC(Mtxf *matrices, s32 count)
for (i = 0, j = 0; i < count; i++, j += sizeof(Mtxf))
{
matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), (Mtxf *)((u32)matrices + j), &sp40);
matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), (Mtxf *)((uintptr_t)matrices + j), &sp40); /* D298/M2 */
sp40.m[3][0] -= g_CurrentPlayer->current_model_pos.f[0];
sp40.m[3][1] -= g_CurrentPlayer->current_model_pos.f[1];
+17 -11
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#ifdef PORT
#include <stdio.h>
#include <stdlib.h>
@@ -189,7 +194,7 @@ void bondviewLoadSetupIntroSection(void)
startpadcount++;
}
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroSpawn));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroSpawn));
}
break;
@@ -226,7 +231,7 @@ void bondviewLoadSetupIntroSection(void)
}
}
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroItem));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroItem));
}
break;
@@ -237,7 +242,7 @@ void bondviewLoadSetupIntroSection(void)
give_cur_player_ammo(((struct SetupIntroAmmo*)intro_record)->ammo_type, ((struct SetupIntroAmmo*)intro_record)->ammo_amount);
}
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroAmmo));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroAmmo));
}
break;
@@ -256,7 +261,7 @@ void bondviewLoadSetupIntroSection(void)
intro_swirl->unk14.fval = intro_swirl->unk14.ival / M_U16_MAX_VALUE_F;
intro_swirl->unk18.fval = intro_swirl->unk18.ival / M_U16_MAX_VALUE_F;
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroSwirl));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroSwirl));
}
break;
@@ -264,7 +269,7 @@ void bondviewLoadSetupIntroSection(void)
{
g_IntroAnimationIndex = ((struct SetupIntroAnim*)intro_record)->intro_anim;
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroAnim));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroAnim));
}
break;
@@ -272,7 +277,7 @@ void bondviewLoadSetupIntroSection(void)
{
g_CurrentPlayer->bondtype = ((struct SetupIntroCuff*)intro_record)->bondtype;
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCuff));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroCuff));
}
break;
@@ -311,7 +316,7 @@ void bondviewLoadSetupIntroSection(void)
}
}
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCamera));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroCamera));
}
break;
@@ -333,7 +338,7 @@ void bondviewLoadSetupIntroSection(void)
if (watch_time_0);
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroWatch));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroWatch));
}
break;
@@ -351,7 +356,7 @@ void bondviewLoadSetupIntroSection(void)
credits++;
}
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCredits));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroCredits));
}
break;
@@ -360,7 +365,7 @@ void bondviewLoadSetupIntroSection(void)
#ifdef DEBUG
ossyncprintf("unknown bondstart type %d!\n",intro_record->type);
#endif
intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroEmpty));
intro_record = (struct SetupIntroEmpty*)((uintptr_t)intro_record + sizeof(struct SetupIntroEmpty));
}
break;
@@ -389,7 +394,8 @@ void bondviewLoadSetupIntroSection(void)
{
rand_camera_index--;
#ifdef PORT
ptr_random06cam_entry = (struct SetupIntroCamera *)(uintptr_t)ptr_random06cam_entry->prev;
/* D88/D298: prev is a u32 holding the truncated host pointer; re-base. */
ptr_random06cam_entry = PORT_N64PTR(struct SetupIntroCamera, ptr_random06cam_entry->prev);
#else
ptr_random06cam_entry = ptr_random06cam_entry->prev;
#endif
+16 -6
View File
@@ -33,6 +33,16 @@
#include "model.h"
#include "tex.h"
/* D298/M2: animation_table_ptrs1/2 slots and vtxstore_allocate() results hold
* N64/window addresses as s32; re-base where they become pointers. Identity at
* PORT_ADDR_BASE == 0. */
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#ifdef PORT
#include <stdio.h>
#include <stdlib.h>
@@ -69,7 +79,7 @@ static s32 d193aAnimIndex(void *anim) {
s32 i;
if (anim == NULL) return -1;
for (i = 0; animation_table_ptrs1[i] != 0; i++) {
if ((void *)(uintptr_t)(u32)animation_table_ptrs1[i] == anim) return i;
if (PORT_N64PTR(void, animation_table_ptrs1[i]) == anim) return i;
}
return -1;
}
@@ -2491,11 +2501,11 @@ s32 chrTick(PropRecord *prop)
{
if (D_8002C904)
{
if (((ModelAnimation *)animation_table_ptrs1[g_AnimationTablePointerCountRelated]) != ((ModelAnimation *)1))
if (PORT_N64PTR(ModelAnimation, animation_table_ptrs1[g_AnimationTablePointerCountRelated]) != PORT_N64PTR(ModelAnimation, 1))
{
if (objecthandlerGetModelAnim(model) != ((ModelAnimation *)animation_table_ptrs1[g_AnimationTablePointerCountRelated]))
if (objecthandlerGetModelAnim(model) != PORT_N64PTR(ModelAnimation, animation_table_ptrs1[g_AnimationTablePointerCountRelated]))
{
modelSetAnimation(model, (ModelAnimation *)animation_table_ptrs1[g_AnimationTablePointerCountRelated], 0, 0.0f, 0.5f, 0.0f);
modelSetAnimation(model, PORT_N64PTR(ModelAnimation, animation_table_ptrs1[g_AnimationTablePointerCountRelated]), 0, 0.0f, 0.5f, 0.0f);
}
}
}
@@ -3581,7 +3591,7 @@ after_opcode:
if (((ModelRwData_DisplayList_CollisionRecord *) rwdata)->Vertices == ((ModelRoData_DisplayList_CollisionRecord *) node)->Vertices)
{
newvertices = (Vertex *) vtxstore_allocate(((ModelRoData_DisplayList_CollisionRecord *) node)->numVertices, 0xcccc, 0, 0);
newvertices = PORT_N64PTR(Vertex, vtxstore_allocate(((ModelRoData_DisplayList_CollisionRecord *) node)->numVertices, 0xcccc, 0, 0));
if (newvertices != NULL)
{
@@ -3598,7 +3608,7 @@ after_opcode:
if ((relatedrwdata != NULL) && (relatedrwdata->Vertices == relatedrodata->Vertices))
{
newvertices = (Vertex *) vtxstore_allocate(relatedrodata->numVertices, 0xcccc, 0, 0);
newvertices = PORT_N64PTR(Vertex, vtxstore_allocate(relatedrodata->numVertices, 0xcccc, 0, 0));
if (newvertices != NULL)
{
+6 -1
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include <bondtypes.h>
#include "cheat.h"
#include "chr.h"
@@ -100,7 +105,7 @@ struct Model *makeonebody(s32 body, s32 head, struct ModelFileHeader *bodyHeader
if ((headHeader != 0) && (c_item_entries[body].hasHead == 0))
{
bodyHeader->numRecords -= headHeader->numRecords;
modelAttachHead(model, opcode, headHeader);
modelAttachHead(model, PORT_N64PTR(ModelNode, opcode), headHeader);
if ((sunglasses == 0) && ((s32) headHeader->numSwitches > 0))
{
+25 -13
View File
@@ -45,6 +45,16 @@
#define PUN_ATTACK_ITEM(punchr, field) ((s32)(punchr)->field.attack_item)
#endif
/* D298/M2: `(s32)&ANIM_DATA_x + (s32)&ptr_animation_table->data` is an N64
* address, and animation_table_ptrs1[] slots hold N64 addresses; re-base where
* such a value becomes a pointer. Identity at PORT_ADDR_BASE == 0. */
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
point2d D_800309F0 = {0, 0};
// forward declarations
@@ -507,7 +517,7 @@ void chrlvKneelingAnimationRelated(ChrRecord *self)
if ((s32)objecthandlerGetModelAnim(self->model) == (s32)&ANIM_DATA_fire_kneel_forward_one_handed_weapon_slow + (s32)&ptr_animation_table->data)
{
modelSetAnimation(self->model, (struct ModelAnimation*)((s32)&ANIM_DATA_fire_kneel_forward_one_handed_weapon_slow + (s32)&ptr_animation_table->data), (s32) self->model->gunhand, 109.0f, chrlvGetGuard007SpeedRating(self, 0.5f, 0.8f), 16.0f);
modelSetAnimation(self->model, PORT_N64PTR(struct ModelAnimation, (s32)&ANIM_DATA_fire_kneel_forward_one_handed_weapon_slow + (s32)&ptr_animation_table->data), (s32) self->model->gunhand, 109.0f, chrlvGetGuard007SpeedRating(self, 0.5f, 0.8f), 16.0f);
modelSetAnimEndFrame(self->model, 140.0f);
}
else
@@ -625,7 +635,7 @@ void chrlvPerformAnimationForActor(ChrRecord *self, s32 animID, s32 startframe,
}
#endif
modelSetAnimation(self->model, (void *)animation_table_ptrs1[animID], (bitfield & ANIM_MIRROR) != 0, startframef, phi_f0, (f32)interpol_time60);
modelSetAnimation(self->model, PORT_N64PTR(void, animation_table_ptrs1[animID]), (bitfield & ANIM_MIRROR) != 0, startframef, phi_f0, (f32)interpol_time60);
if (endframe >= 0)
{
@@ -2822,7 +2832,7 @@ s32 chrlvExplosionDamage(ChrRecord *self, coord3d *arg1, f32 damage, s32 arg3)
modelSetAnimation(
self_model,
(struct ModelAnimation *) ((s32)sp38->anonymous_0 + (s32)&ptr_animation_table->data),
PORT_N64PTR(struct ModelAnimation, (s32)sp38->anonymous_0 + (s32)&ptr_animation_table->data),
sp38->anonymous_1,
sp38->anonymous_3,
sp38->anonymous_2,
@@ -4986,7 +4996,9 @@ bool if_actor_able_set_on_path(ChrRecord *self, s32 pathid)
{
if (pathid && chrIsNotDeadOrShot(self))
{
set_actor_on_path(self, pathid);
/* D298/M2: callers pass a window PathRecord* truncated through this
* s32 param (chrai.c / aicommands.def); re-base on the read. */
set_actor_on_path(self, PORT_N64PTR(struct patrol_path, pathid));
return TRUE;
}
@@ -5075,7 +5087,7 @@ void chrlvTickStand(ChrRecord *self)
modelSetAnimation(
self->model,
// awkward fix: addu instruction is backwards
(struct ModelAnimation *)((s32)&ANIM_DATA_walking_unarmed + (s32)&ptr_animation_table->data),
PORT_N64PTR(struct ModelAnimation, (s32)&ANIM_DATA_walking_unarmed + (s32)&ptr_animation_table->data),
i,
0.0f,
0.5f,
@@ -5083,14 +5095,14 @@ void chrlvTickStand(ChrRecord *self)
modelSetAnimEndFrame(
self->model,
(((u16*)((s32)&ANIM_DATA_walking_unarmed + (s32)&ptr_animation_table->data))[2] - 1));
(PORT_N64PTR(u16, (s32)&ANIM_DATA_walking_unarmed + (s32)&ptr_animation_table->data)[2] - 1));
}
else if ((right != NULL) || (left != NULL))
{
modelSetAnimation(
self->model,
// awkward fix: addu instruction is backwards
(struct ModelAnimation *)((s32)&ANIM_DATA_walking + (s32)&ptr_animation_table->data),
PORT_N64PTR(struct ModelAnimation, (s32)&ANIM_DATA_walking + (s32)&ptr_animation_table->data),
left != NULL,
0.0f,
0.5f,
@@ -5098,7 +5110,7 @@ void chrlvTickStand(ChrRecord *self)
modelSetAnimEndFrame(
self->model,
(((u16*)((s32)&ANIM_DATA_walking + (s32)&ptr_animation_table->data))[2] - 1));
(PORT_N64PTR(u16, (s32)&ANIM_DATA_walking + (s32)&ptr_animation_table->data)[2] - 1));
}
}
else if (self->act_stand.face_entitytype & 0x10)
@@ -5450,13 +5462,13 @@ void chrlvTickDie(ChrRecord *self)
{
modelSetAnimation(
model,
(void*)((s32)&ANIM_DATA_jump_backwards + (s32)&ptr_animation_table->data),
PORT_N64PTR(void, (s32)&ANIM_DATA_jump_backwards + (s32)&ptr_animation_table->data),
objecthandlerGetModelGunhand(model) == 0,
50.0f,
0.3f,
(((u16*)((s32)&ANIM_DATA_jump_backwards + (s32)&ptr_animation_table->data))[2] - 1.0f) - 50.0f);
((PORT_N64PTR(u16, (s32)&ANIM_DATA_jump_backwards + (s32)&ptr_animation_table->data))[2] - 1.0f) - 50.0f);
modelSetAnimSpeed(model, 0.5f, (((u16*)((s32)&ANIM_DATA_jump_backwards + (s32)&ptr_animation_table->data))[2] - 1.0f) - 50.0f);
modelSetAnimSpeed(model, 0.5f, ((PORT_N64PTR(u16, (s32)&ANIM_DATA_jump_backwards + (s32)&ptr_animation_table->data))[2] - 1.0f) - 50.0f);
return;
}
@@ -9160,8 +9172,8 @@ void chrlvTravelTick(ChrRecord *self, coord3d *arg1, StandTile *arg2, struct way
if ((phi_s3 == NULL) || ((self->hidden & CHRHIDDEN_OFFSCREEN_PATROL) != 0))
{
if ((objecthandlerGetModelAnim(self->model) == (struct ModelAnimation *)((s32)&ANIM_DATA_idle_unarmed + (s32)&ptr_animation_table->data))
|| (objecthandlerGetModelAnim(self->model) == (struct ModelAnimation *)((s32)&ANIM_DATA_idle + (s32)&ptr_animation_table->data)))
if ((objecthandlerGetModelAnim(self->model) == PORT_N64PTR(struct ModelAnimation, (s32)&ANIM_DATA_idle_unarmed + (s32)&ptr_animation_table->data))
|| (objecthandlerGetModelAnim(self->model) == PORT_N64PTR(struct ModelAnimation, (s32)&ANIM_DATA_idle + (s32)&ptr_animation_table->data)))
{
if (self->actiontype == ACT_PATROL)
{
+6 -1
View File
@@ -33,6 +33,11 @@
#include <random.h>
#include <snd.h>
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#ifdef PORT
#include <stdlib.h>
#endif
@@ -1192,7 +1197,7 @@ void ai(PropDefHeaderRecord *Entityp, PROP_TYPE EntityType)
{
zero = 0; // debug value maybe?
/* D32/D33: table holds s32 offsets; cast at use site. */
modelSetAnimation(AircraftEntityp->model, (ModelAnimation *)animation_table_ptrs2[anim_id], zero, startframe, 0.5f, (s32)ai->INTERPOL_TIME60);
modelSetAnimation(AircraftEntityp->model, PORT_N64PTR(ModelAnimation, animation_table_ptrs2[anim_id]), zero, startframe, 0.5f, (s32)ai->INTERPOL_TIME60);
if (endframe >= 0)
{
modelSetAnimEndFrame(AircraftEntityp->model, endframe);
+6 -1
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include <PR/os.h>
#include <PR/gbi.h>
#include <gbi_extension.h>
@@ -1734,7 +1739,7 @@ Gfx *explosionRenderFlyingParticles(Gfx *gdl)
for (i = 0; i < max_particles; i++)
{
// HACK: regalloc has instructions backwards.
particles = (struct FlyingParticles *)(u32)g_FlyingParticlesBuffer + i;
particles = (struct FlyingParticles *)PORT_N64PTR(void, g_FlyingParticlesBuffer) + i;
if (particles->unk00 > 0)
{
+19 -15
View File
@@ -51,6 +51,10 @@
#include "model.h"
#ifdef PORT
#include "hudaspect.h" /* D335 front-end pillarbox under native widescreen */
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
@@ -983,8 +987,8 @@ Gfx *frontPrintText(Gfx *gdl, s32 *x, s32 *y, s8 *text, s32 second_font_table, s
x,
y,
text,
second_font_table,
first_font_table,
PORT_N64PTR(struct fontchar, second_font_table),
PORT_N64PTR(struct font, first_font_table),
arg6,
(textglowR.r << 0x18) | (textglowG.r << 0x10) | (textglowB.r << 8) | textglowA.r,
view_x,
@@ -999,8 +1003,8 @@ Gfx *frontPrintText(Gfx *gdl, s32 *x, s32 *y, s8 *text, s32 second_font_table, s
x,
y,
text,
second_font_table,
first_font_table,
PORT_N64PTR(struct fontchar, second_font_table),
PORT_N64PTR(struct font, first_font_table),
arg6,
view_x,
view_y,
@@ -1526,7 +1530,7 @@ Gfx *display_aligned_white_text_to_screen(Gfx *dl, s32 arg1, s32 arg2, s32 halig
x = arg1 - ((s32) (halign * sp48) / 2);
y = arg2 - ((s32) (valign * sp4C) / 2);
return textRender(dl, &x, &y, text, arg6, arg7, -1, viGetX(), viGetY(), 0, 0);
return textRender(dl, &x, &y, text, PORT_N64PTR(struct fontchar, arg6), PORT_N64PTR(struct font, arg7), -1, viGetX(), viGetY(), 0, 0);
}
@@ -2179,7 +2183,7 @@ void load_walletbond(void)
b = (struct ModelNode *)mnode;
srecord = b->Data;
arg0 = (s32)srecord->BaseAddr + ((s32)srecord->Primary & 0xffffff);
arg0 = PORT_N64PTR(Gfx, (s32)srecord->BaseAddr + ((s32)srecord->Primary & 0xffffff));
bgApplyDynamicCCRMLUT(arg0, NULL, CCRMLUT_WALLETBOND);
}
}
@@ -7485,7 +7489,7 @@ Gfx *constructor_menu0D_missioncomplete(Gfx *DL)
x = 0x37;
y = 0xDC;
DL = frontPrintText(DL, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0xFF, viGetX(), viGetY(), 0, 0);
strcpy(stagename, frontGetPlayersFavoriteWeaponInHand(0, 0));
strcpy(stagename, PORT_N64PTR(char, frontGetPlayersFavoriteWeaponInHand(0, 0)));
if ((array_favweapon[0][0] > 0) && (array_favweapon[0][1] == array_favweapon[0][0]))
{
temp = strlen(stagename)-1;
@@ -7846,16 +7850,16 @@ Gfx *constructor_menu16_nocontrollers(Gfx *DL)
if ((numContCon == 0) || (numContCon == 1) || (numContCon == 2) || (numContCon == 3)) {
text = langGet(getStringID(LTITLE, TITLE_STR_118_NOCONT)); //NO CONTROLLER IN CONTROLLER SOCKET 1
}
textMeasure(&y2, &x2, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0);
textMeasure(&y2, &x2, PORT_N64PTR(char, text), ptrFontZurichBoldChars, ptrFontZurichBold, 0);
x = 0xDC - (x2 >> 1);
y = 0x99 - (y2 >> 1);
#ifdef BUGFIX_R1
if (j_text_trigger) {
DL = textRenderOutlined(DL, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x8000FF, viGetX(), viGetY(), 0, 0);
DL = textRenderOutlined(DL, &x, &y, PORT_N64PTR(char, text), ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x8000FF, viGetX(), viGetY(), 0, 0);
}
else {
#endif
DL = textRender(DL, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0);
DL = textRender(DL, &x, &y, PORT_N64PTR(char, text), ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0);
#ifdef BUGFIX_R1
}
#endif
@@ -7864,16 +7868,16 @@ Gfx *constructor_menu16_nocontrollers(Gfx *DL)
if ((numContCon == 0) || (numContCon == 1) || (numContCon == 2) || (numContCon == 3)) {
text = langGet(getStringID(LTITLE, TITLE_STR_119_ATTACHCONT)); //PLEASE POWER OFF AND ATTACH A CONTROLLER
}
textMeasure(&y2, &x2, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0);
textMeasure(&y2, &x2, PORT_N64PTR(char, text), ptrFontZurichBoldChars, ptrFontZurichBold, 0);
x = 0xDC - (x2 >> 1);
y = 0xB1 - (y2 >> 1);
#ifdef BUGFIX_R1
if (j_text_trigger) {
DL = textRenderOutlined(DL, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x8000FF, viGetX(), viGetY(), 0, 0);
DL = textRenderOutlined(DL, &x, &y, PORT_N64PTR(char, text), ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x8000FF, viGetX(), viGetY(), 0, 0);
}
else {
#endif
DL = textRender(DL, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0);
DL = textRender(DL, &x, &y, PORT_N64PTR(char, text), ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0);
#ifdef BUGFIX_R1
}
#endif
@@ -8098,7 +8102,7 @@ void init_menu18_displaycast(void)
#else
modelSetAnimPlaySpeed(cast_model, 0.5f, 0);
#endif
modelSetAnimation(cast_model, animation_table_ptrs1[intro_animation_table[randomly_selected_intro_animation].animID], flip, intro_animation_table[randomly_selected_intro_animation].startframeoffset, intro_animation_table[randomly_selected_intro_animation].playback_speed, 0.0f);
modelSetAnimation(cast_model, PORT_N64PTR(ModelAnimation, animation_table_ptrs1[intro_animation_table[randomly_selected_intro_animation].animID]), flip, intro_animation_table[randomly_selected_intro_animation].startframeoffset, intro_animation_table[randomly_selected_intro_animation].playback_speed, 0.0f);
g_MenuTimer = 0;
cast_camera_dist_start = ((((f32) ((u32) randomGetNext())) * (1.0f / U32_MAX)) * 80.0f) + 70.0f;
@@ -8761,7 +8765,7 @@ void menu_init(void)
{
if (viGetFrameBuf2() == (cfb_16[1]))
{
viSetFrameBuf2(ptr_menu_videobuffer);
viSetFrameBuf2(PORT_N64PTR(u8, ptr_menu_videobuffer));
}
viSetAspect(MENU_INIT_ASPECT_440);
+12 -7
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include "include/limits.h"
#include <bondconstants.h>
#include <bondtypes.h>
@@ -6256,14 +6261,14 @@ Gfx *generate_ammo_total_microcode(Gfx *gdl)
if (imageoffset_r != 0)
{
imageoffset_r += globalbank_rdram_offset;
gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset_r, (getPlayer_c_screenleft() + getPlayer_c_screenwidth()) - (f32)rightx, -1.0f,
gdl = set_rgba_redirect_generate_microcode(gdl, PORT_N64PTR(u8, imageoffset_r), (getPlayer_c_screenleft() + getPlayer_c_screenwidth()) - (f32)rightx, -1.0f,
#if defined(VERSION_EU)
(viGetViewTop() + viGetViewHeight()) - 30, 0,
#else
(viGetViewTop() + viGetViewHeight()) - 20, 0,
#endif
ammo_related[ammotype].IconYOffset, 1);
textwidth_r = ((u8 *)imageoffset_r)[4];
textwidth_r = (PORT_N64PTR(u8, imageoffset_r))[4];
}
gdl = microcode_constructor(gdl);
@@ -6328,14 +6333,14 @@ Gfx *generate_ammo_total_microcode(Gfx *gdl)
if (imageoffset_l != 0)
{
imageoffset_l += globalbank_rdram_offset;
gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset_l, getPlayer_c_screenleft() + (f32)leftx, -1.0f,
gdl = set_rgba_redirect_generate_microcode(gdl, PORT_N64PTR(u8, imageoffset_l), getPlayer_c_screenleft() + (f32)leftx, -1.0f,
#if defined(VERSION_EU)
(viGetViewTop() + viGetViewHeight()) - 30, 1,
#else
(viGetViewTop() + viGetViewHeight()) - 20, 1,
#endif
ammo_related[ammotype].IconYOffset, 1);
textwidth_l = ((u8 *)imageoffset_l)[4];
textwidth_l = (PORT_N64PTR(u8, imageoffset_l))[4];
}
gdl = microcode_constructor(gdl);
@@ -6426,12 +6431,12 @@ Gfx *gunDrawWatchAmmoDisplay(Gfx *gdl)
// Draw the ammo icon
#if defined(VERSION_EU)
gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset, 200.0f, 208.0f, (viGetViewTop() + viGetViewHeight()) - 30, 0, ammo_related[ammotype].IconYOffset, 1);
gdl = set_rgba_redirect_generate_microcode(gdl, PORT_N64PTR(u8, imageoffset), 200.0f, 208.0f, (viGetViewTop() + viGetViewHeight()) - 30, 0, ammo_related[ammotype].IconYOffset, 1);
#else
gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset, 200.0f, 180.0f, (viGetViewTop() + viGetViewHeight()) - 20, 0, ammo_related[ammotype].IconYOffset, 1);
gdl = set_rgba_redirect_generate_microcode(gdl, PORT_N64PTR(u8, imageoffset), 200.0f, 180.0f, (viGetViewTop() + viGetViewHeight()) - 20, 0, ammo_related[ammotype].IconYOffset, 1);
#endif
textwidth = ((u8 *)imageoffset)[4];
textwidth = (PORT_N64PTR(u8, imageoffset))[4];
}
gdl = microcode_constructor(gdl);
+2 -2
View File
@@ -414,7 +414,7 @@ s32 texAlignIndices(u8 *src, s32 width, s32 height, s32 format, u8 *dst)
src++;
}
outptr = (u8 *)(((u32)outptr + 7) & ~7);
outptr = (u8 *)(((uintptr_t)outptr + 7) & ~(uintptr_t)7);
}
return outptr - dst;
@@ -2462,7 +2462,7 @@ void texLoadFromDisplayList(Gfx *gdl, struct texpool *arg1)
if (bytes[0] == G_SETTIMG && bytes[4] == 0xab && bytes[5] == 0xcd)
#endif
{
texLoad((u32 *)((s32)bytes + 4), arg1);
texLoad((u32 *)(bytes + 4), arg1);
}
bytes += 8;
+27 -4
View File
@@ -4,6 +4,10 @@
#include "image_bank.h"
#ifdef PORT
#include <gimgfixup.h>
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
// bss
@@ -16,7 +20,11 @@ s32 img_bitcount;
//8008D0AC
s32 dword_CODE_bss_8008D0AC;
//8008D0B0;
#if defined(PORT)
uintptr_t globalbank_rdram_offset; /* D298/M2: host-based, see image_bank.h */
#else
s32 globalbank_rdram_offset;
#endif
//8008D0B4;
s32 *pGlobalimagetable;
//8008D0B8;
@@ -89,7 +97,14 @@ extern u8* _GlobalimagetableSegmentRomStart;
void texSetBitstring(s32 pos) {
#if defined(PORT)
/* D298/M2: callers pass a host pointer through this s32 parameter, which
* truncates it. Because PORT_ADDR_BASE is 4 GiB-aligned the low 32 bits
* are the N64/window offset, so re-base them. Identity at base 0. */
img_curpos = (u8 *)portN64ToHost((u32)pos);
#else
img_curpos = pos;
#endif
img_curdatatable = 0;
img_bitcount = 0;
}
@@ -167,7 +182,7 @@ extern Gfx* globalDL_0x900;
extern Gfx* globalDL_0x9a8;
extern Gfx* globalDL_0xa50;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
/* D39 (docs/dev/findings.md): on N64 all 49 symbols above link inside the
* Globalimagetable segment at physical 0x02xxxxxx (ge007.ld), so
* `globalbank_rdram_offset + (u32)&sym` rebases each onto pGlobalimagetable.
@@ -244,16 +259,24 @@ void texReset(void)
pGlobalimagetable = mempAllocBytesInBank(size + 0x1000, MEMPOOL_STAGE);
pGlobalimagetable = ((u32)pGlobalimagetable + 0xFFFU) & 0xFFFFF000;
romCopy(pGlobalimagetable, &_GlobalimagetableSegmentRomStart, size);
romCopy(PORT_N64PTR(void, pGlobalimagetable), &_GlobalimagetableSegmentRomStart, size);
#ifdef PORT
/* D68 (docs/dev/findings.md): the ROM copy is N64 big-endian; convert
* the CPU-interpreted u32 fields (IMAGESEG Gfx w1 words and
* sImageTableEntry.index) to host order before any code reads them. */
gimgFixupGlobalimagetable((u8 *)pGlobalimagetable);
gimgFixupGlobalimagetable((u8 *)PORT_N64PTR(void, pGlobalimagetable));
#endif
#if defined(PORT)
/* D298/M2: store a HOST-based offset. GIMG_OFF(sym) adds 0x02000000, so
* `globalbank_rdram_offset + GIMG_OFF(sym)` is then a live host pointer.
* `- 0x02000000` is the 64-bit equivalent of the original 32-bit
* `+ 0xFE000000` wraparound (which relied on mod-2^32 cancellation). */
globalbank_rdram_offset = (uintptr_t)portN64ToHost((u32)pGlobalimagetable) - 0x02000000UL;
#else
globalbank_rdram_offset = (u32)pGlobalimagetable + 0xFE000000;
#endif
genericimage = (void *) (globalbank_rdram_offset + GIMG_OFF(s_genericimage));
impactimages = (void *) (globalbank_rdram_offset + GIMG_OFF(s_impactimages));
explosion_smokeimages = (void *) (globalbank_rdram_offset + GIMG_OFF(s_explosion_smokeimages));
@@ -321,6 +344,6 @@ void texReset(void)
/* D68: explosion.c executes the compiled globalDL_0xNNN shadows via
* g_ExplosionDisplayLists[]; copy the IMAGESEG words that texLoad()
* patched in the ROM copy over into those arrays. */
gimgSyncCompiledGlobalDLs((u8 *)pGlobalimagetable);
gimgSyncCompiledGlobalDLs((u8 *)PORT_N64PTR(void, pGlobalimagetable));
#endif
}
+7
View File
@@ -25,7 +25,14 @@ extern struct sImageTableEntry *flareimage5;
extern u8* img_curpos;
extern s32 img_bitcount;
extern s32 *pGlobalimagetable;
#if defined(PORT)
/* D298/M2: holds a host-based RDRAM offset (pGlobalimagetable - 0x02000000)
* so `globalbank_rdram_offset + GIMG_OFF(sym)` is a live host pointer in the
* DRAM window. s32 on N64 (see image_bank.c). */
extern uintptr_t globalbank_rdram_offset;
#else
extern s32 globalbank_rdram_offset;
#endif
void texReset(void);
u32 texReadBits(s32 bitCount);
+7 -2
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include <math.h>
#include <bondtypes.h>
#include "chr.h"
@@ -166,7 +171,7 @@ void sets_a_bunch_of_BONDdata_values_to_default(void)
{
sub_GAME_7F0062C0(
// match hack: addu address calculated backwards
(void*)((s32)g_BondMoveAnimationSetup[i].anim_id + (s32)&ptr_animation_table->data),
PORT_N64PTR(void, (s32)g_BondMoveAnimationSetup[i].anim_id + (s32)&ptr_animation_table->data),
(s32)g_BondMoveAnimationSetup[i].loopframe,
(s32)g_BondMoveAnimationSetup[i].endframe,
&spD0);
@@ -194,7 +199,7 @@ void sets_a_bunch_of_BONDdata_values_to_default(void)
modelSetAnimation(
&g_CurrentPlayer->model,
// match hack: addu address calculated backwards
(struct ModelAnimation *) ((s32)g_BondMoveAnimationSetup[g_CurrentPlayer->headanim].anim_id + (s32)&ptr_animation_table->data),
(struct ModelAnimation *) PORT_N64PTR(void, (s32)g_BondMoveAnimationSetup[g_CurrentPlayer->headanim].anim_id + (s32)&ptr_animation_table->data),
0,
g_BondMoveAnimationSetup[g_CurrentPlayer->headanim].loopframe,
0.5f,
+13 -3
View File
@@ -6,6 +6,16 @@
#include "math.h"
#include "math_floor.h"
/* D298/M2: these tables store animation addresses as N64 values (s32/union
* offset) that are then cast to pointers. Re-base when the pointer is formed;
* identity at PORT_ADDR_BASE == 0. */
#if defined(PORT)
#include "port_addr.h"
#define ANI_ADDR(x) ((void *)portN64ToHost((u32)(x)))
#else
#define ANI_ADDR(x) ((void *)(x))
#endif
/**
* Gets the number of currently allocated heads and bodies
@@ -108,7 +118,7 @@ s32 initResolveAnimGroupTable(struct weapon_firing_animation_table *animconfig)
do
{
config->anim.anim = (struct ModelAnimation *)(((0, animoffset)) + ((s32)ptr_animation_table));
config->anim.anim = (struct ModelAnimation *)ANI_ADDR(((0, animoffset)) + ((s32)ptr_animation_table));
endframe = floorFloatToInt(config->unk04);
angle16 = sub_GAME_7F0001F0(config->anim.anim, 0, endframe) & 0xffff;
duration = config->unk04;
@@ -186,7 +196,7 @@ s32 initResolveAnimTable(struct StruckAnim *entries)
count++;
entry++;
ptr_animation_table_addr = (struct StruckAnim *)(&ptr_animation_table);
entry[-1].struck_anim = (ModelAnimation *)((*((s32 *)entries)) + (0, address));
entry[-1].struck_anim = (ModelAnimation *)ANI_ADDR((*((s32 *)entries)) + (0, address));
}
while (entry->struck_anim != 0);
}
@@ -196,7 +206,7 @@ s32 initResolveAnimTable(struct StruckAnim *entries)
#define ANIM_PTR(anim) \
((ModelAnimation *)((s32)&anim + ((s32)ptr_animation_table)))
((ModelAnimation *)ANI_ADDR((s32)&anim + ((s32)ptr_animation_table)))
#define ANIM_FRAC(anim) \
((((f32)sub_GAME_7F000290(ANIM_PTR(anim), 0, ANIM_PTR(anim)->unk04 - 1)) * 0.10000001f) / \
+9 -3
View File
@@ -6,6 +6,12 @@
/* D33: ROM-file endianness fixup for the animation data segment (port layer). */
#include "romdata.h"
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
//bss
@@ -256,15 +262,15 @@ void expand_ani_table_entries(s32** arg0)
while (*var_v0 != 0) {
if (*var_v0 != 1) {
*var_v0 = (s32)((s32)*var_v0 + (s32)(&ptr_animation_table->data));
((struct anim_entry *)*var_v0)->unk08 += (s32)&ptr_animation_table->data;
((struct anim_entry *)*var_v0)->unk10 += (s32)&ptr_animation_table->data;
PORT_N64PTR(struct anim_entry, *var_v0)->unk08 += (s32)&ptr_animation_table->data;
PORT_N64PTR(struct anim_entry, *var_v0)->unk10 += (s32)&ptr_animation_table->data;
}
var_v0++;
}
for (var_v0 = (s32 *)arg0; *var_v0 != 0; var_v0++) {
if (*var_v0 != 1) {
*(s32 *)*var_v0 += (s32)&_animation_entriesSegmentRomStart;
*PORT_N64PTR(s32, *var_v0) += (s32)&_animation_entriesSegmentRomStart;
}
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ void initModelHitEntryFreeList(void)
entries[i].prev = &entries[i - 1];
}
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
// D40: N64 g_ModelHitEntriesPenultimate labels entry 598 of the pool; on PC the
// placeholder symbol is not emitted, so take the address directly.
((ModelHitEntry *)g_ModelHitEntries)[MODELHITENTRIES_LEN - 1].prev = &entries[MODELHITENTRIES_LEN - 2];
+31 -14
View File
@@ -11,6 +11,7 @@
#ifdef PORT
#include "envflag.h" /* cached getenv for hot-path probes */
#endif
#include "port_addr.h" /* D298/M2: DRAM window base */
extern resource_lookup_data_entry resource_lookup_data_array[]; /* ob.c */
static void langFixupLoadedBank(char *name, void *p)
@@ -21,6 +22,16 @@ static void langFixupLoadedBank(char *name, void *p)
}
#endif
/* g_LangBanks[] holds N64 DRAM addresses as s32 (they must fit s32, see
* memp.h / D298). Re-base only where a slot becomes a pointer; identity at
* PORT_ADDR_BASE == 0, so Windows/Linux are unchanged. */
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
// bss
//CODE.bss:8008C640
s32 g_LangBanks[45];
@@ -267,13 +278,13 @@ void langInit(void) {
g_LangBanks[LOPTIONS] = _fileNameLoadToBank(LnameX_lookuptable[LOPTIONS][j_text_trigger], FILELOADMETHOD_DEFAULT, 0x100, MEMPOOL_PERMANENT);
g_LangBanks[LMISC] = _fileNameLoadToBank(LnameX_lookuptable[LMISC][j_text_trigger], FILELOADMETHOD_DEFAULT, 0x100, MEMPOOL_PERMANENT);
#ifdef PORT
langFixupLoadedBank(LnameX_lookuptable[LGUN][j_text_trigger], (void *)g_LangBanks[LGUN]);
langFixupLoadedBank(LnameX_lookuptable[LTITLE][j_text_trigger], (void *)g_LangBanks[LTITLE]);
langFixupLoadedBank(LnameX_lookuptable[LMPMENU][j_text_trigger], (void *)g_LangBanks[LMPMENU]);
langFixupLoadedBank(LnameX_lookuptable[LPROPOBJ][j_text_trigger], (void *)g_LangBanks[LPROPOBJ]);
langFixupLoadedBank(LnameX_lookuptable[LMPWEAPONS][j_text_trigger], (void *)g_LangBanks[LMPWEAPONS]);
langFixupLoadedBank(LnameX_lookuptable[LOPTIONS][j_text_trigger], (void *)g_LangBanks[LOPTIONS]);
langFixupLoadedBank(LnameX_lookuptable[LMISC][j_text_trigger], (void *)g_LangBanks[LMISC]);
langFixupLoadedBank(LnameX_lookuptable[LGUN][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LGUN]));
langFixupLoadedBank(LnameX_lookuptable[LTITLE][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LTITLE]));
langFixupLoadedBank(LnameX_lookuptable[LMPMENU][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LMPMENU]));
langFixupLoadedBank(LnameX_lookuptable[LPROPOBJ][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LPROPOBJ]));
langFixupLoadedBank(LnameX_lookuptable[LMPWEAPONS][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LMPWEAPONS]));
langFixupLoadedBank(LnameX_lookuptable[LOPTIONS][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LOPTIONS]));
langFixupLoadedBank(LnameX_lookuptable[LMISC][j_text_trigger], PORT_N64PTR(void, g_LangBanks[LMISC]));
#endif
}
@@ -381,7 +392,7 @@ void langLoadToAddr(u32 id)
{
g_LangBanks[id] = _fileNameLoadToBank(LnameX_lookuptable[id][j_text_trigger],1,0x100,MEMPOOL_STAGE);
#ifdef PORT
langFixupLoadedBank(LnameX_lookuptable[id][j_text_trigger], (void *)g_LangBanks[id]);
langFixupLoadedBank(LnameX_lookuptable[id][j_text_trigger], PORT_N64PTR(void, g_LangBanks[id]));
#endif
}
@@ -390,7 +401,7 @@ void langLoadToBank(int id,u8 *target,int size)
{
g_LangBanks[id] = _fileNameLoadToAddr(LnameX_lookuptable[id][j_text_trigger],1,target,size);
#ifdef PORT
langFixupLoadedBank(LnameX_lookuptable[id][j_text_trigger], (void *)g_LangBanks[id]);
langFixupLoadedBank(LnameX_lookuptable[id][j_text_trigger], PORT_N64PTR(void, g_LangBanks[id]));
#endif
}
@@ -417,16 +428,22 @@ u8 * langGet(s32 slotID)
return NULL;
}
#endif
u32 * textbank_ptr = g_LangBanks[slotID >> 10]; /* get the text file bank ID index the text ptr table */
u32 * textbank_ptr = PORT_N64PTR(u32, g_LangBanks[slotID >> 10]); /* get the text file bank ID index the text ptr table */
#ifdef PORT
/* D129 cont.: g_LangBanks[] is s32 and only populated for banks the
* current flow has loaded. A bare `-level_XX` boot that reaches the
* cast/credits text path (Cuba, bondviewRenderCredits, D76) hits a bank
* slot that was never filled -> stale/garbage non-NULL value -> fault on
* the table read below. Reject anything that is not a plausible mapped
* DRAM address. */
if ((uintptr_t)textbank_ptr < 0x10000 || (uintptr_t)textbank_ptr >= 0x400000000ULL) {
return NULL;
* DRAM address. D298/M2: the DRAM window is shifted by PORT_ADDR_BASE on
* macOS, so the bounds move with it (identity at PORT_ADDR_BASE == 0). */
{
uintptr_t t = (uintptr_t)textbank_ptr;
uintptr_t lo = (uintptr_t)PORT_ADDR_BASE + 0x10000u;
uintptr_t hi = (uintptr_t)PORT_ADDR_BASE + 0x400000000ULL;
if (t < lo || t >= hi) {
return NULL;
}
}
#endif
#ifdef PORT
@@ -437,7 +454,7 @@ u8 * langGet(s32 slotID)
d65first = 0;
for (int b = 0; b < 45; b++)
if (g_LangBanks[b])
osSyncPrintf("D65 bank %d = %p\n", b, (void *)g_LangBanks[b]);
osSyncPrintf("D65 bank %d = %p\n", b, PORT_N64PTR(void, g_LangBanks[b]));
}
if (!textbank_ptr)
osSyncPrintf("D65 langGet slotID=0x%08x bank=%d ptr=NULL\n", (unsigned)slotID, slotID >> 10);
+43 -19
View File
@@ -13,6 +13,16 @@
#include "initunk_005520.h"
#include "math_asinfacosf.h"
#include "math_floor.h"
/* D298/M2: ModelAnimation.bitDescriptors/bitStream are u32 fields holding N64
* addresses (D32: the blob base is added by expand_ani_table_entries). Re-base
* where they become pointers; identity at PORT_ADDR_BASE == 0. */
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include "math_ceil.h"
#include "math_unk_05A9E0.h"
#include "objecthandler.h"
@@ -78,6 +88,11 @@ Model *modelmgrInstantiateModel(ModelFileHeader *header)
/* PC port (D53.2): this buffer is used as a struct Model via the
* same type-pun as g_ModelSlots; on PC that struct is 0xE8 bytes,
* not the N64 0x20 slot size. */
{
static int fb = 0;
osSyncPrintf("modelmgr: STAGE model fallback #%d (numRecords=%d)\n",
++fb, (int)header->numRecords);
}
model = mempAllocBytesInBank(sizeof(struct Model), MEMPOOL_STAGE);
#else
model = mempAllocBytesInBank(0x20, MEMPOOL_STAGE);
@@ -1028,7 +1043,7 @@ u16 modelAnimReadRootMotionValue(ModelAnimation *anim, s32 fieldIndex, s32 extra
u8 bitsThisRead;
result = 0;
desc = (ModelAnimBitField *)anim->bitDescriptors + fieldIndex; // D32: u32 -> ptr
desc = PORT_N64PTR(struct ModelAnimBitField, anim->bitDescriptors) + fieldIndex; // D32: u32 -> ptr (D298/M2 re-base)
bitsRemaining = desc->bitCount;
if (bitsRemaining > 0)
@@ -1036,7 +1051,7 @@ u16 modelAnimReadRootMotionValue(ModelAnimation *anim, s32 fieldIndex, s32 extra
totalBitOffset = extraBitOffset + desc->bitOffset;
byteIndex = totalBitOffset >> 3;
totalBitOffset &= 7;
byteptr = (u8 *)anim->bitStream + byteIndex; // D32: u32 -> ptr
byteptr = PORT_N64PTR(u8, anim->bitStream) + byteIndex; // D32: u32 -> ptr (D298/M2 re-base)
bitsThisRead = 8 - totalBitOffset;
if (bitsRemaining >= bitsThisRead)
@@ -1713,24 +1728,24 @@ void process_02_position(ModelRenderData *arg0, Model *model, ModelNode *node)
rot1 = D_80036094;
sub_GAME_7F06DEC0(jointnum.v, model->gunhand, skeleton, model->anim, model->unk34, &rot1);
sub_GAME_7F06DEC0(jointnum.v, model->gunhand, skeleton, model->anim, PORT_N64PTR(u8, model->unk34), &rot1);
if (model->unk2c != 0.0f)
{
rot2 = D_800360A0;
sub_GAME_7F06DEC0(jointnum.v, model->gunhand, skeleton, model->anim, model->unk38, &rot2);
sub_GAME_7F06DEC0(jointnum.v, model->gunhand, skeleton, model->anim, PORT_N64PTR(u8, model->unk38), &rot2);
sub_GAME_7F06D160(&rot1, &rot2, model->unk2c);
}
if (model->unk84 != 0.0f)
{
rot3 = D_800360AC;
sub_GAME_7F06DEC0(jointnum.v, model->unk25, skeleton, model->anim2, model->unk64, &rot3);
sub_GAME_7F06DEC0(jointnum.v, model->unk25, skeleton, model->anim2, PORT_N64PTR(u8, model->unk64), &rot3);
if (model->unk5c != 0.0f)
{
rot4 = D_800360B8;
sub_GAME_7F06DEC0(jointnum.v, model->unk25, skeleton, model->anim2, model->unk68, &rot4);
sub_GAME_7F06DEC0(jointnum.v, model->unk25, skeleton, model->anim2, PORT_N64PTR(u8, model->unk68), &rot4);
sub_GAME_7F06D160(&rot3, &rot4, model->unk5c);
}
@@ -6209,7 +6224,12 @@ s32 loadAnimationFrame(ModelAnimation* anim, s32 frame, ModelSkeleton* unused)
s32 ret;
s32 source;
s32 frameSize;
#if defined(PORT)
/* D298/M2: keep the buffer address at full pointer width (D59 buffer). */
uintptr_t dest;
#else
u32 dest;
#endif
u32 size;
ret = 0;
@@ -6223,8 +6243,12 @@ s32 loadAnimationFrame(ModelAnimation* anim, s32 frame, ModelSkeleton* unused)
else if (D_80036414 != NULL) // should never be NULL after initAnimationsBuffer is called
{
// Get dest from this D_80036414 which points to an array. Align to 16 bytes.
#if defined(PORT)
dest = ((uintptr_t)(D_80036414->animBufferPtr2 + 15) >> 4) * 16;
#else
dest = ((u32) (D_80036414->animBufferPtr2 + 15) >> 4) * 16;
ret = dest;
#endif
ret = (s32)dest;
// Get source of this animation in ROM with the offset of the frame we'll load
source = anim->address + (frame * frameSize);
@@ -6239,14 +6263,14 @@ s32 loadAnimationFrame(ModelAnimation* anim, s32 frame, ModelSkeleton* unused)
size = ((u32) (frameSize + 15) >> 4) * 16;
// This copies one animation frame from ROM to the destination in RAM
romCopy((void* ) dest, (void* ) source, size);
romCopy((void *)dest, (void *)source, size);
// Increment this which serves nothing
D_80036414->uselessPointer += 1;
// Set this to point to the end of the copied frame
// This allows to copy another frame after this one
D_80036414->animBufferPtr2 = dest + size;
D_80036414->animBufferPtr2 = (void *)(dest + size);
}
return ret;
}
@@ -6268,7 +6292,7 @@ void modelResetAnimationsScratchBuffer(void)
#define PROMOTE(var) \
if (var) \
var = (void *)((u32)var + diff)
var = (void *)portN64ToHost((u32)var + diff)
#ifdef PORT
/* PC port (D43/D45): Vertex.LinkedTo is a raw vma (u32), not a pointer —
@@ -6320,7 +6344,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
{
ModelRoData_DisplayListRecord* rodata = &node->Data->DisplayList;
PROMOTE(rodata->Vertices);
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6338,7 +6362,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
PROMOTE(rodata->CollisionVertices[i].LinkedTo);
#endif
}
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6362,7 +6386,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
PROMOTE(rodata->Children[i].unk04);
}
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6381,14 +6405,14 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
PROMOTE(rodata->Children[i].unk04);
}
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
case MODELNODE_OPCODE_OP06:
{
ModelRoData_Op06Record* rodata = &node->Data->Op06;
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6426,7 +6450,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
{
ModelRoData_Op11Record* rodata = &node->Data->Op11;
PROMOTE(rodata->unk0c[15]);
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6434,7 +6458,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
{
ModelRoData_GunfireRecord* rodata = &node->Data->Gunfire;
PROMOTE(rodata->Image);
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6443,7 +6467,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
ModelRoData_ShadowRecord* rodata = &node->Data->Shadow;
PROMOTE(rodata->image);
PROMOTE(rodata->Header);
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
@@ -6451,7 +6475,7 @@ void modelPromoteNodeOffsetsToPointers(ModelNode *node, u32 vma, u32 fileramaddr
{
ModelRoData_DisplayListPrimaryRecord* rodata = &node->Data->DisplayListPrimary;
PROMOTE(rodata->Vertices);
rodata->BaseAddr = (void *)fileramaddr;
rodata->BaseAddr = PORT_N64PTR(void, fileramaddr);
break;
}
+11 -5
View File
@@ -17,6 +17,12 @@
#include "mp_music.h"
#include "file.h"
#include "assets/obseg/text/LmpmenuE.h"
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#ifdef REFRESH_PAL
#define MPMENU_YOFF 8 /* PAL: every text row sits 8 pixels lower */
@@ -1407,7 +1413,7 @@ Gfx *mp_watch_menu_display(Gfx *gdl)
// Must remain a comma expression for matching
h2 = (s32) langGet(getStringID(LMPMENU, MPMENU_STR_1D_KILLS)), /* KILLS */
sprintf(rankbuffer, ascii_pnum_KILLS, (char *) q, curplayernum + 1, (char *) h2); /* -> "P<n> KILLS" */
sprintf(rankbuffer, ascii_pnum_KILLS, PORT_N64PTR(char, q), curplayernum + 1, PORT_N64PTR(char, h2)); /* -> "P<n> KILLS" */
textMeasure(&textheight, &textwidth, rankbuffer, ptrFontBankGothicChars, ptrFontBankGothic, 0);
x = ((viGetViewLeft() + two_player_x_offset) - (textwidth >> 1)) + 80;
@@ -1477,7 +1483,7 @@ Gfx *mp_watch_menu_display(Gfx *gdl)
// Must remain a comma expression for matching.
h2 = (s32) langGet(getStringID(LMPMENU, MPMENU_STR_1E_LOSSES)), /* LOSSES */
sprintf(rankbuffer, ascii_pnum_LOSSES, (char *) q, curplayernum + 1, (char *) h2); /* -> "P<n> LOSSES" */
sprintf(rankbuffer, ascii_pnum_LOSSES, PORT_N64PTR(char, q), curplayernum + 1, PORT_N64PTR(char, h2)); /* -> "P<n> LOSSES" */
textMeasure(&textheight, &textwidth, rankbuffer, ptrFontBankGothicChars, ptrFontBankGothic, 0);
x = ((viGetViewLeft() + two_player_x_offset) - (textwidth >> 1)) + 80;
@@ -1593,7 +1599,7 @@ Gfx *mp_watch_menu_display(Gfx *gdl)
y = (viGetViewTop() - (fav_textheight >> 1)) + (37 + MPMENU_YOFF);
viewleft = viGetX(); h1 = viGetY();
gdl = textRender(gdl, &x, &y, text, ptrFontBankGothicChars, ptrFontBankGothic, 0x00ff00b0, viewleft, h1, 0, 0);
text = frontGetPlayersFavoriteWeaponInHand(curplayernum, 0);
text = PORT_N64PTR(char, frontGetPlayersFavoriteWeaponInHand(curplayernum, 0));
textMeasure(&fav_textheight, &fav_textwidth, text, ptrFontBankGothicChars, ptrFontBankGothic, 0);
x = ((viGetViewLeft() + fav_x_offset) - (fav_textwidth >> 1)) + 80;
x2 = viGetViewTop();
@@ -1615,7 +1621,7 @@ Gfx *mp_watch_menu_display(Gfx *gdl)
if (g_CurrentPlayer->ptr_text_first_mp_award)
{
text = (char *) g_CurrentPlayer->ptr_text_first_mp_award;
text = PORT_N64PTR(char, g_CurrentPlayer->ptr_text_first_mp_award);
textMeasure(&fav_textheight, &fav_textwidth, text, ptrFontBankGothicChars, ptrFontBankGothic, 0);
x = ((viGetViewLeft() + fav_x_offset) - (fav_textwidth >> 1)) + 80;
y = (viGetViewTop() - (fav_textheight >> 1)) + (75 + MPMENU_YOFF);
@@ -1626,7 +1632,7 @@ Gfx *mp_watch_menu_display(Gfx *gdl)
if (g_CurrentPlayer->ptr_text_second_mp_award)
{
text = (char *) g_CurrentPlayer->ptr_text_second_mp_award;
text = PORT_N64PTR(char, g_CurrentPlayer->ptr_text_second_mp_award);
textMeasure(&fav_textheight, &fav_textwidth, text, ptrFontBankGothicChars, ptrFontBankGothic, 0);
x = ((viGetViewLeft() + fav_x_offset) - (fav_textwidth >> 1)) + 80;
y = (viGetViewTop() - (fav_textheight >> 1)) + (88 + MPMENU_YOFF);
+1 -1
View File
@@ -4,7 +4,7 @@
#include "model.h"
// bss
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
// D40: the N64 placeholder chain below (g_ModelHitEntries .. g_ModelHitEntriesPenultimate)
// forms one contiguous 600 x 20-byte ModelHitEntry pool in CODE.bss. On x86-64
// ModelHitEntry is 40 bytes (two pointer pairs), so initModelHitEntryFreeList()
+7 -2
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include "chrobjdata.h"
#include "image.h"
#include "math_asinfacosf.h"
@@ -56,7 +61,7 @@ void sub_GAME_7F0762E0(ModelFileHeader *objheader, u8 *name, u8 *dst, struct tex
delta = ((s32) ((romremaining + filedata) - (s32) name)) - ((s32) (((u8 *) objheader->Switches) + (((u32) gdl) & 0x00ffffff)));
texCopyGdls((Gfx *) (((u8 *) objheader->Switches) + (((u32) gdl) & 0x00ffffff)), (Gfx *) ((romremaining + filedata) - (s32) name), (s32) name);
texCopyGdls((Gfx *) (((u8 *) objheader->Switches) + (((u32) gdl) & 0x00ffffff)), PORT_N64PTR(Gfx, (romremaining + filedata) - (s32) name), (s32) name);
texLoadFromModelFileHeader(objheader, buffer);
@@ -86,7 +91,7 @@ void sub_GAME_7F0762E0(ModelFileHeader *objheader, u8 *name, u8 *dst, struct tex
name = (u8 *) (((s32) (((u8 *) objheader->Switches) + (replacementgdl & 0x00ffffff))) - filedata);
fileSetSize(filenum, (u8 *) filedata, (((s32) name + 0xf) & (~0xf)), dst == 0);
fileSetSize(filenum, PORT_N64PTR(u8, filedata), (((s32) name + 0xf) & (~0xf)), dst == 0);
}
}
+54 -48
View File
@@ -17,6 +17,12 @@
#include "glass.h"
#include "frametiming.h"
#include "assets/obseg/text/LoptionE.h"
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#define WATCH_BACKGROUND_VERTEX_COUNT 30
@@ -1937,30 +1943,30 @@ Gfx *draw_abort_cancel_confirm(Gfx *gdl)
if (watch_item_is_actively_selected != 0)
{
textMeasure(&sp60, &sp64, sp54, pFontChars, pFontFile, 0);
textMeasure(&sp60, &sp64, PORT_N64PTR(char, sp54), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
gdl = textRender(gdl, &sp7C, &sp70, sp54, pFontChars, pFontFile, 0xA0FFA0F0, sp64, sp60, 0, 0);
gdl = textRender(gdl, &sp7C, &sp70, PORT_N64PTR(char, sp54), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xA0FFA0F0, sp64, sp60, 0, 0);
if (D_800409A4 != 0)
{
gdl = textRenderOutlined(gdl, &sp78, &sp6C, sp50, pFontChars, pFontFile, -1, 0x7000A0, viGetX(), viGetY(), 0, 0);
gdl = textRender(gdl, &sp74, &sp68, sp4C, pFontChars, pFontFile, 0xFF00B0, viGetX(), viGetY(), 0, 0);
gdl = textRenderOutlined(gdl, &sp78, &sp6C, PORT_N64PTR(char, sp50), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), -1, 0x7000A0, viGetX(), viGetY(), 0, 0);
gdl = textRender(gdl, &sp74, &sp68, PORT_N64PTR(char, sp4C), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xFF00B0, viGetX(), viGetY(), 0, 0);
}
else
{
if (D_800409A4 == 0)
{
gdl = textRender(gdl, &sp78, &sp6C, sp50, pFontChars, pFontFile, 0xFF00B0, viGetX(), viGetY(), 0, 0);
gdl = textRenderOutlined(gdl, &sp74, &sp68, sp4C, pFontChars, pFontFile, -1, 0x7000A0, viGetX(), viGetY(), 0, 0);
gdl = textRender(gdl, &sp78, &sp6C, PORT_N64PTR(char, sp50), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xFF00B0, viGetX(), viGetY(), 0, 0);
gdl = textRenderOutlined(gdl, &sp74, &sp68, PORT_N64PTR(char, sp4C), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), -1, 0x7000A0, viGetX(), viGetY(), 0, 0);
}
}
}
else
{
textMeasure(&sp60, &sp64, sp54, pFontChars, pFontFile, 0);
gdl = textRender(gdl, &sp7C, &sp70, sp54, pFontChars, pFontFile, 0x800080, sp64, sp60, 0, 0);
gdl = textRender(gdl, &sp78, &sp6C, sp50, pFontChars, pFontFile, 0x800080, viGetX(), viGetY(), 0, 0);
gdl = textRender(gdl, &sp74, &sp68, sp4C, pFontChars, pFontFile, 0x800080, viGetX(), viGetY(), 0, 0);
textMeasure(&sp60, &sp64, PORT_N64PTR(char, sp54), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
gdl = textRender(gdl, &sp7C, &sp70, PORT_N64PTR(char, sp54), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0x800080, sp64, sp60, 0, 0);
gdl = textRender(gdl, &sp78, &sp6C, PORT_N64PTR(char, sp50), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0x800080, viGetX(), viGetY(), 0, 0);
gdl = textRender(gdl, &sp74, &sp68, PORT_N64PTR(char, sp4C), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0x800080, viGetX(), viGetY(), 0, 0);
}
return gdl;
@@ -1996,10 +2002,10 @@ Gfx *draw_text_mission_status(Gfx *gdl)
}
gdl = microcode_constructor(gdl);
textMeasure(&sp5C, &sp58, txtptr_1, pFontChars, pFontFile, 0);
textMeasure(&sp5C, &sp58, PORT_N64PTR(char, txtptr_1), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
sp64 = 0x51;
sp60 = YOFFSET_MISSIONSTATUS;
gdl = textRender(gdl, &sp64, &sp60, txtptr_1, pFontChars, pFontFile, 0xFF00B0, sp58, sp5C, 0, 0);
gdl = textRender(gdl, &sp64, &sp60, PORT_N64PTR(char, txtptr_1), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xFF00B0, sp58, sp5C, 0, 0);
if (j_text_trigger)
{
@@ -2012,8 +2018,8 @@ Gfx *draw_text_mission_status(Gfx *gdl)
sp64 = sp64 + sp58 + joffset + 4;
sp60 = sp60 - sp5C;
textMeasure(&sp5C, &sp58, txtptr_2, pFontChars, pFontFile, 0);
gdl = textRender(gdl, &sp64, &sp60, txtptr_2, pFontChars, pFontFile, sp4C, sp58, sp5C, 0, 0);
textMeasure(&sp5C, &sp58, PORT_N64PTR(char, txtptr_2), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
gdl = textRender(gdl, &sp64, &sp60, PORT_N64PTR(char, txtptr_2), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), sp4C, sp58, sp5C, 0, 0);
gdl = draw_abort_cancel_confirm(gdl);
return gdl;
@@ -2053,8 +2059,8 @@ Gfx *draw_text_q_watch_v201_beta(Gfx *gdl)
pFontFile = ptrFontBankGothic;
pFontChars = ptrFontBankGothicChars;
gdl = microcode_constructor(gdl);
textMeasure(&sp48, &sp44, txtptr, pFontChars, pFontFile, 0);
gdl = textRender(gdl, &sp50, &sp4C, txtptr, pFontChars, pFontFile, 0xFF00B0, sp44, sp48, 0, 0);
textMeasure(&sp48, &sp44, PORT_N64PTR(char, txtptr), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
gdl = textRender(gdl, &sp50, &sp4C, PORT_N64PTR(char, txtptr), PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xFF00B0, sp44, sp48, 0, 0);
return gdl;
}
@@ -2189,16 +2195,16 @@ Gfx* draw_current_hand_item_and_ammo(Gfx* gdl) {
#else
sp88 = 0xBC;
#endif
textMeasure(&sp84, &sp80, text, sp78, sp7C, 0);
gdl = textRender(gdl, &sp8C, &sp88, text, sp78, sp7C, 0xFF00B0, sp80, sp84, 0, 0);
textMeasure(&sp84, &sp80, text, PORT_N64PTR(struct fontchar, sp78), PORT_N64PTR(struct font, sp7C), 0);
gdl = textRender(gdl, &sp8C, &sp88, text, PORT_N64PTR(struct fontchar, sp78), PORT_N64PTR(struct font, sp7C), 0xFF00B0, sp80, sp84, 0, 0);
#if defined(LEFTOVERDEBUG)
sp88 = 0xAA;
#else
sp88 = 0xC6;
#endif
textMeasure(&sp84, &sp80, text2, sp78, sp7C, 0);
gdl = textRender(gdl, &sp8C, &sp88, text2, sp78, sp7C, 0xFF00B0, sp80, sp84, 0, 0);
textMeasure(&sp84, &sp80, text2, PORT_N64PTR(struct fontchar, sp78), PORT_N64PTR(struct font, sp7C), 0);
gdl = textRender(gdl, &sp8C, &sp88, text2, PORT_N64PTR(struct fontchar, sp78), PORT_N64PTR(struct font, sp7C), 0xFF00B0, sp80, sp84, 0, 0);
return gdl;
}
@@ -2428,11 +2434,11 @@ Gfx *draw_watch_inventory_page(Gfx *gdl, Mtx *param_2)
gdl = microcode_constructor(gdl);
textMeasure(&textheight, &textwidth, string_builder_allocation, pFontChars2, pFontFile2, LINEHEIGHT());
textMeasure(&textheight, &textwidth, string_builder_allocation, PORT_N64PTR(struct fontchar, pFontChars2), PORT_N64PTR(struct font, pFontFile2), LINEHEIGHT());
gdl = microcode_constructor_related_to_menus(gdl, 0x4E, WATCH_INV_BASE_Y(), textwidth + 0x4E, (LINEHEIGHT() * 5) + WATCH_INV_BASE_Y(), 0);
gdl = textRender(gdl, &x1, &y1, string_builder_allocation, pFontChars2, pFontFile2, 0xAA00B0, textwidth + 1, LINEHEIGHT() * 5, watch_inventory_text_y, LINEHEIGHT());
gdl = textRender(gdl, &x1, &y1, string_builder_allocation, PORT_N64PTR(struct fontchar, pFontChars2), PORT_N64PTR(struct font, pFontFile2), 0xAA00B0, textwidth + 1, LINEHEIGHT() * 5, watch_inventory_text_y, LINEHEIGHT());
gdl = microcode_constructor_related_to_menus(gdl, 0x4B, temp_s0_3, textwidth + 0x52, (LINEHEIGHT() + temp_s0_3) - 2, 0x800050);
@@ -2454,22 +2460,22 @@ Gfx *draw_watch_inventory_page(Gfx *gdl, Mtx *param_2)
gdl = microcode_constructor(gdl);
textMeasure(&y2, &x2, formattedString, pFontChars, pFontFile, 0);
textMeasure(&y2, &x2, formattedString, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
if (watch_inventory_text_is_settled != 0)
{
textMeasure(&y2, &x2, invItemName, pFontChars, pFontFile, LINEHEIGHT());
textMeasure(&y2, &x2, invItemName, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), LINEHEIGHT());
x1 = 0x4E;
y1 = (LINEHEIGHT() * 2) + WATCH_INV_BASE_Y();
if (D_800409C4 == 0)
{
gdl = textRender(gdl, &x1, &y1, invItemName, pFontChars, pFontFile, 0xA0FFA0F0, x2, 0x64, 0, LINEHEIGHT());
gdl = textRender(gdl, &x1, &y1, invItemName, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xA0FFA0F0, x2, 0x64, 0, LINEHEIGHT());
}
else
{
gdl = textRenderOutlined(gdl, &x1, &y1, invItemName, pFontChars, pFontFile, -1, 0x7000A0, x2 + 1, 0x64, 0, LINEHEIGHT());
gdl = textRenderOutlined(gdl, &x1, &y1, invItemName, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), -1, 0x7000A0, x2 + 1, 0x64, 0, LINEHEIGHT());
}
sub_GAME_7F0A8378();
@@ -2521,7 +2527,7 @@ Gfx *unused_draw_watch_inventory_page(Gfx *gdl, Mtx *param_2) {
game_options_inventory_navigation();
gdl = microcode_constructor(gdl);
textMeasure(&sp58, &sp54, long_name, pFontChars, pFontFile, 0);
textMeasure(&sp58, &sp54, long_name, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
sp70 = ((s32) (0xAA - sp54) / 2) + 0x4B;
temp_2 = sp70;
@@ -2534,16 +2540,16 @@ Gfx *unused_draw_watch_inventory_page(Gfx *gdl, Mtx *param_2) {
sub_GAME_7F0A8378();
if (D_800409C4 == 0)
{
gdl = textRender(gdl, &sp70, &sp6C, long_name, pFontChars, pFontFile, 0xA0FFA0F0, sp54, 0x64, 0, 0);
gdl = textRender(gdl, &sp70, &sp6C, long_name, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xA0FFA0F0, sp54, 0x64, 0, 0);
}
else
{
gdl = textRenderOutlined(gdl, &sp70, &sp6C, long_name, pFontChars, pFontFile, -1, 0x7000A0, sp54 + 1, 0x64, 0, 0);
gdl = textRenderOutlined(gdl, &sp70, &sp6C, long_name, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), -1, 0x7000A0, sp54 + 1, 0x64, 0, 0);
}
}
else
{
gdl = textRender(gdl, &sp70, &sp6C, long_name, pFontChars, pFontFile, 0xAA00B0, sp54, 0x64, 0, 0);
gdl = textRender(gdl, &sp70, &sp6C, long_name, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0xAA00B0, sp54, 0x64, 0, 0);
}
}
@@ -3260,11 +3266,11 @@ Gfx *display_text_buttons_dual_control(Gfx *gdl)
if (joyGetButtons(PLAYER_1, Z_TRIG))
{
gdl = draw_options_labels(gdl, 0x5A, YOFFSET_5, textptr_aux, -1, 1, 0x7000A0, 0, 0, 0x3000B0, 0);
gdl = draw_options_labels(gdl, 0x5A, YOFFSET_5, PORT_N64PTR(char, textptr_aux), -1, 1, 0x7000A0, 0, 0, 0x3000B0, 0);
}
else
{
gdl = draw_options_labels(gdl, 0x5A, YOFFSET_5, textptr_aux, 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 0);
gdl = draw_options_labels(gdl, 0x5A, YOFFSET_5, PORT_N64PTR(char, textptr_aux), 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 0);
}
if ((g_CurrentPlayer->cur_player_control_type_0 == CONTROLLER_CONFIG_PLENTY) || (g_CurrentPlayer->cur_player_control_type_0 == CONTROLLER_CONFIG_DOMINO))
@@ -3276,7 +3282,7 @@ Gfx *display_text_buttons_dual_control(Gfx *gdl)
textptr_aux = langGet(getStringID(LOPTIONS, OPTION_STR_06_LOOK_LF)); //look
}
gdl = draw_options_labels(gdl, 0x5A, YOFFSET_4, textptr_aux, 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 0);
gdl = draw_options_labels(gdl, 0x5A, YOFFSET_4, PORT_N64PTR(char, textptr_aux), 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 0);
if (joyGetButtons(1, A_BUTTON))
{
@@ -3307,11 +3313,11 @@ Gfx *display_text_buttons_dual_control(Gfx *gdl)
if (joyGetButtons(1, Z_TRIG))
{
gdl = draw_options_labels(gdl, 0xE6, YOFFSET_5, textptr_aux, -1, 1, 0x7000A0, 0, 0, 0x3000B0, 1);
gdl = draw_options_labels(gdl, 0xE6, YOFFSET_5, PORT_N64PTR(char, textptr_aux), -1, 1, 0x7000A0, 0, 0, 0x3000B0, 1);
}
else
{
gdl = draw_options_labels(gdl, 0xE6, YOFFSET_5, textptr_aux, 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 1);
gdl = draw_options_labels(gdl, 0xE6, YOFFSET_5, PORT_N64PTR(char, textptr_aux), 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 1);
}
if ((g_CurrentPlayer->cur_player_control_type_0 == CONTROLLER_CONFIG_PLENTY) || (g_CurrentPlayer->cur_player_control_type_0 == CONTROLLER_CONFIG_DOMINO))
@@ -3323,7 +3329,7 @@ Gfx *display_text_buttons_dual_control(Gfx *gdl)
textptr_aux = langGet(getStringID(LOPTIONS, OPTION_STR_05_MOVE_LF)); //move
}
gdl = draw_options_labels(gdl, 0xE6, YOFFSET_4, textptr_aux, 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 1);
gdl = draw_options_labels(gdl, 0xE6, YOFFSET_4, PORT_N64PTR(char, textptr_aux), 0xAA00B0, 0, -1, 0, 0, 0x3000B0, 1);
return gdl;
}
@@ -3554,14 +3560,14 @@ Gfx *draw_watch_control_options_page(Gfx *gdl, Mtx *param_2) {
}
}
textMeasure(&sp50, &sp54, textptr, pFontChars, pFontFile, 0);
textMeasure(&sp50, &sp54, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
if ((watch_item_is_actively_selected != 0) && (controller_options_index == CONTROLLER_OPTIONS_INDEX_STYLE))
{
gdl = textRenderOutlined(gdl, &sp5C, &sp58, textptr, pFontChars, pFontFile, phi_s1, 0x7000A0, sp54 + 1, sp50, 0, 0);
gdl = textRenderOutlined(gdl, &sp5C, &sp58, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), phi_s1, 0x7000A0, sp54 + 1, sp50, 0, 0);
} else
{
gdl = textRender(gdl, &sp5C, &sp58, textptr, pFontChars, pFontFile, phi_s1, sp54, sp50, 0, 0);
gdl = textRender(gdl, &sp5C, &sp58, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), phi_s1, sp54, sp50, 0, 0);
}
gdl = draw_controller_style_text(gdl);
@@ -3585,14 +3591,14 @@ Gfx *draw_watch_control_options_page(Gfx *gdl, Mtx *param_2) {
}
}
textMeasure(&sp50, &sp54, textptr, pFontChars, pFontFile, 0);
textMeasure(&sp50, &sp54, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
if ((watch_item_is_actively_selected != 0) && (controller_options_index == CONTROLLER_OPTIONS_INDEX_INPUTS))
{
gdl = textRenderOutlined(gdl, &sp5C, &sp58, textptr, pFontChars, pFontFile, phi_s1, 0x7000A0, sp54 + 1, sp50, 0, 0);
gdl = textRenderOutlined(gdl, &sp5C, &sp58, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), phi_s1, 0x7000A0, sp54 + 1, sp50, 0, 0);
} else
{
gdl = textRender(gdl, &sp5C, &sp58, textptr, pFontChars, pFontFile, phi_s1, sp54, sp50, 0, 0);
gdl = textRender(gdl, &sp5C, &sp58, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), phi_s1, sp54, sp50, 0, 0);
}
}
@@ -3859,15 +3865,15 @@ Gfx *draw_watch_game_options_page(Gfx *gdl, Mtx *param_2) {
}
}
textMeasure(&sp48, &sp4C, textptr, pFontChars, pFontFile, 0);
textMeasure(&sp48, &sp4C, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
if ((watch_item_is_actively_selected != 0) && (game_options_index == 0))
{
gdl = textRenderOutlined(gdl, &sp54, &sp50, textptr, pFontChars, pFontFile, sp5C, 0x7000A0, sp4C + 1, sp48, 0, 0);
gdl = textRenderOutlined(gdl, &sp54, &sp50, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), sp5C, 0x7000A0, sp4C + 1, sp48, 0, 0);
}
else
{
gdl = textRender(gdl, &sp54, &sp50, textptr, pFontChars, pFontFile, sp5C, sp4C, sp48, 0, 0);
gdl = textRender(gdl, &sp54, &sp50, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), sp5C, sp4C, sp48, 0, 0);
}
sp5C = 0xFF00B0;
@@ -3886,15 +3892,15 @@ Gfx *draw_watch_game_options_page(Gfx *gdl, Mtx *param_2) {
}
}
textMeasure(&sp48, &sp4C, textptr, pFontChars, pFontFile, 0);
textMeasure(&sp48, &sp4C, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), 0);
if ((watch_item_is_actively_selected != 0) && (game_options_index == 1))
{
gdl = textRenderOutlined(gdl, &sp54, &sp50, textptr, pFontChars, pFontFile, sp5C, 0x7000A0, sp4C + 1, sp48, 0, 0);
gdl = textRenderOutlined(gdl, &sp54, &sp50, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), sp5C, 0x7000A0, sp4C + 1, sp48, 0, 0);
}
else
{
gdl = textRender(gdl, &sp54, &sp50, textptr, pFontChars, pFontFile, sp5C, sp4C, sp48, 0, 0);
gdl = textRender(gdl, &sp54, &sp50, textptr, PORT_N64PTR(struct fontchar, pFontChars), PORT_N64PTR(struct font, pFontFile), sp5C, sp4C, sp48, 0, 0);
}
gdl = draw_toggle_options(gdl);
+6 -1
View File
@@ -1,4 +1,9 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include <R4300.h>
#include "tex.h"
#include "image.h"
@@ -364,7 +369,7 @@ void texSelect(Gfx **gdlptr, struct sImageTableEntry *tconfig, u32 arg2, s32 arg
texLoad((s32 *)tconfig, NULL);
}
aa = PHYS_TO_K0(tconfig->index);
aa = PORT_N64PTR(u16, tconfig->index); /* D298/M2: index holds the pool address */
tex = texFindInPool((aa)[-4], NULL);
if (tconfig->level == 0)
+20 -20
View File
@@ -1324,19 +1324,19 @@ void proplvreset2(enum LEVELID stageId)
* The setup file stores every internal reference as a byte offset from the start of the file,
* so rebase them all onto the RAM copy at local_stage.
*/
g_CurrentSetup.pathwaypoints = (void *) (((u32) local_stage) + ((u32) local_stage->pathwaypoints));
g_CurrentSetup.waypointgroups = (void *) (((u32) local_stage) + ((u32) local_stage->waypointgroups));
g_CurrentSetup.intro = (void *) (((u32) local_stage) + ((u32) local_stage->intro));
g_CurrentSetup.propDefs = (void *) (((u32) local_stage) + ((u32) local_stage->propDefs));
g_CurrentSetup.patrolpaths = (void *) (((u32) local_stage) + ((u32) local_stage->patrolpaths));
g_CurrentSetup.ailists = (void *) (((u32) local_stage) + ((u32) local_stage->ailists));
g_CurrentSetup.pads = (void *) (((u32) local_stage) + ((u32) local_stage->pads));
g_CurrentSetup.boundpads = (void *) (((u32) local_stage) + ((u32) local_stage->boundpads));
g_CurrentSetup.pathwaypoints = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->pathwaypoints));
g_CurrentSetup.waypointgroups = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->waypointgroups));
g_CurrentSetup.intro = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->intro));
g_CurrentSetup.propDefs = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->propDefs));
g_CurrentSetup.patrolpaths = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->patrolpaths));
g_CurrentSetup.ailists = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->ailists));
g_CurrentSetup.pads = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->pads));
g_CurrentSetup.boundpads = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->boundpads));
// Pad names and bound names are optional. An offset of 0 means absent.
if (local_stage->padnames != 0)
{
g_CurrentSetup.padnames = (void *) (((u32) local_stage) + ((u32) local_stage->padnames));
g_CurrentSetup.padnames = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->padnames));
}
else
{
@@ -1345,7 +1345,7 @@ void proplvreset2(enum LEVELID stageId)
if (local_stage->boundpadnames != 0)
{
g_CurrentSetup.boundpadnames = (void *) (((u32) local_stage) + ((u32) local_stage->boundpadnames));
g_CurrentSetup.boundpadnames = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->boundpadnames));
}
else
{
@@ -1356,7 +1356,7 @@ void proplvreset2(enum LEVELID stageId)
{
for (i1 = 0; g_CurrentSetup.pathwaypoints[i1].padID >= 0; i1++)
{
g_CurrentSetup.pathwaypoints[i1].neighbours = (void *) (((u32) g_CurrentSetup.pathwaypoints[i1].neighbours) + ((u32) local_stage));
g_CurrentSetup.pathwaypoints[i1].neighbours = (void *) (((u32) g_CurrentSetup.pathwaypoints[i1].neighbours) + ((uintptr_t) local_stage));
}
}
@@ -1364,8 +1364,8 @@ void proplvreset2(enum LEVELID stageId)
{
for (i2 = 0; g_CurrentSetup.waypointgroups[i2].neighbours; i2++)
{
g_CurrentSetup.waypointgroups[i2].neighbours = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].neighbours) + ((u32) local_stage));
g_CurrentSetup.waypointgroups[i2].waypoints = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].waypoints) + ((u32) local_stage));
g_CurrentSetup.waypointgroups[i2].neighbours = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].neighbours) + ((uintptr_t) local_stage));
g_CurrentSetup.waypointgroups[i2].waypoints = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].waypoints) + ((uintptr_t) local_stage));
}
}
@@ -1376,7 +1376,7 @@ void proplvreset2(enum LEVELID stageId)
{
for (i3 = 0; g_CurrentSetup.ailists[i3].ailist != 0; i3++)
{
g_CurrentSetup.ailists[i3].ailist = (void *) (((u32) g_CurrentSetup.ailists[i3].ailist) + ((u32) local_stage));
g_CurrentSetup.ailists[i3].ailist = (void *) (((u32) g_CurrentSetup.ailists[i3].ailist) + ((uintptr_t) local_stage));
}
}
}
@@ -1385,7 +1385,7 @@ void proplvreset2(enum LEVELID stageId)
{
for (i3 = 0; g_CurrentSetup.patrolpaths[i3].waypoints != NULL; i3++)
{
g_CurrentSetup.patrolpaths[i3].waypoints = (void *) (((u32) g_CurrentSetup.patrolpaths[i3].waypoints) + ((u32) local_stage));
g_CurrentSetup.patrolpaths[i3].waypoints = (void *) (((u32) g_CurrentSetup.patrolpaths[i3].waypoints) + ((uintptr_t) local_stage));
for (i5 = 0; g_CurrentSetup.patrolpaths[i3].waypoints[i5] >= 0; i5++)
{
@@ -1405,7 +1405,7 @@ void proplvreset2(enum LEVELID stageId)
for (; pad->plink != NULL; pad++)
{
pad->plink = (void *) (((u32) local_stage) + ((u32) pad->plink));
pad->plink = (void *) (((uintptr_t) local_stage) + ((u32) pad->plink));
pad->pos.f[0] *= roompos_1;
pad->pos.f[1] *= roompos_1;
pad->pos.f[2] *= roompos_1;
@@ -1460,9 +1460,9 @@ void proplvreset2(enum LEVELID stageId)
/** Ugly matching hack.
* TODO: investigate if there's a way to get rid of this.
*/
if ((((u32) local_stage) ^ 0) + ((u32)vol->plink));
if ((((uintptr_t) local_stage) ^ 0) + ((u32)vol->plink));
vol->plink = (void *) (((u32) local_stage) + ((u32)vol->plink));
vol->plink = (void *) (((uintptr_t) local_stage) + ((u32)vol->plink));
vol->pos.f[0] *= roompos_2;
vol->pos.f[1] *= roompos_2;
vol->pos.f[2] *= roompos_2;
@@ -1497,7 +1497,7 @@ void proplvreset2(enum LEVELID stageId)
{
for (i1 = 0; g_CurrentSetup.padnames[i1].p; i1++)
{
g_CurrentSetup.padnames[i1].p = (void *) (((u32) g_CurrentSetup.padnames[i1].p) + ((u32) local_stage));
g_CurrentSetup.padnames[i1].p = (void *) (((u32) g_CurrentSetup.padnames[i1].p) + ((uintptr_t) local_stage));
}
}
@@ -1508,7 +1508,7 @@ void proplvreset2(enum LEVELID stageId)
for (i1 = 0; g_CurrentSetup.boundpadnames[i1].p; i1++)
{
g_CurrentSetup.boundpadnames[i1].p = (void *) (((u32) g_CurrentSetup.boundpadnames[i1].p) + ((u32) local_stage));
g_CurrentSetup.boundpadnames[i1].p = (void *) (((u32) g_CurrentSetup.boundpadnames[i1].p) + ((uintptr_t) local_stage));
}
}
+6 -1
View File
@@ -7,6 +7,11 @@
---------------------------------------------------------------------*/
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h"
#else
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include <math.h>
#ifdef PORT
#include <stdio.h> /* D202/M-65 diag probe only (doorSndProbe); remove with it */
@@ -5725,7 +5730,7 @@ s32 objTick(struct PropRecord *prop)
#endif
temp_s0_6 = render_pad2F4->model;
if (temp_s0_6->anim == (ModelAnimation *)animation_table_ptrs2[1]) /* D32/D33 */
if (temp_s0_6->anim == PORT_N64PTR(ModelAnimation, animation_table_ptrs2[1])) /* D32/D33 */
{
modelSetAnimTranslationScale(temp_s0_6, 10.438f);
setsubroty(render_pad2F4->model, M_PI_F);
+1 -1
View File
@@ -273,7 +273,7 @@ void rspGfxTaskStart(Gfx *firstGdl, Gfx *gdl, s32 arg2, OSMesg rspReplyMsg)
// Toggles the g_gfxTaskSettingsList to point to altnerate tasks.
// Depends on first assignment taking place (g_gfxTaskSettingsList = g_gfxTaskSettings[0]).
// Not a typo, but probably not best practice.
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
// D32-class: the XOR idiom below truncates exe pointers to u32 on x86-64 and
// yields garbage; toggle explicitly (same semantics: list is always &[0] or &[1]).
g_gfxTaskSettingsList = (g_gfxTaskSettingsList == &g_gfxTaskSettings[0]) ? &g_gfxTaskSettings[1] : &g_gfxTaskSettings[0];
+9 -3
View File
@@ -2,6 +2,12 @@
//#include <bondtypes.h>
#include <deb.h>
#include "stan.h"
#if defined(PORT)
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
#include "bg.h"
#include "chrai.h"
#include "chr.h"
@@ -3239,7 +3245,7 @@ void stanDetermineEOF(struct StanPrefixRecord *file /* canonically r */, s32 ori
assert(*r==0);
#endif
standTileStart = (StandTile *)(((s32)file->ptr_firstroom + delta) - 0x80);
standTileStart = PORT_N64PTR(StandTile, ((s32)file->ptr_firstroom + delta) - 0x80);
ptr_firstroom_0 = (s32)file->ptr_firstroom + delta;
newBase = list_of_tilesizes;
@@ -3249,7 +3255,7 @@ void stanDetermineEOF(struct StanPrefixRecord *file /* canonically r */, s32 ori
{
do
{
*roomPtr = (void *) ((s32) (*roomPtr) + delta);
*roomPtr = PORT_N64PTR(void, (s32)(*roomPtr) + delta);
roomPtr++;
}
while (*roomPtr != NULL);
@@ -3266,7 +3272,7 @@ void stanDetermineEOF(struct StanPrefixRecord *file /* canonically r */, s32 ori
// Fake but required for matching.
if (tile->tail.half);
tile = (StandTile *)((s32)tile
tile = PORT_N64PTR(StandTile, (s32)tile
+ (tileSizes = newBase)[(tile->tail.half >> 0xc) & 0xf]);
}
while (*(s32 *) tile != 0);
+12 -8
View File
@@ -28,6 +28,10 @@
#ifdef PORT
#include <stdlib.h>
#include "port_addr.h"
#else
/* N64 build: the port address window is the identity (see port_addr.h). */
#define PORT_N64PTR(T, x) ((T *)(x))
#endif
@@ -221,7 +225,7 @@ Gfx *sub_GAME_7F007F30(Gfx *gdl, s32 count, Mtxf *matrix)
if (gunbarrelTimer == BOND_EYE_ANIM_START)
{
modelSetAnimation(chrModelInstance, (struct ModelAnimation *) ((s32) &ANIM_DATA_bond_eye_fire + (s32) &ptr_animation_table->data), 0, 2.0f, 0.910000026f, 16.0f);
modelSetAnimation(chrModelInstance, PORT_N64PTR(struct ModelAnimation, (s32) &ANIM_DATA_bond_eye_fire + (s32) &ptr_animation_table->data), 0, 2.0f, 0.910000026f, 16.0f);
}
if (gunbarrelTimer == BOND_EYE_ANIM_SPEEDUP)
@@ -397,7 +401,7 @@ void setupRarewareLogoData(s32 address, s32 size) {
D_8002A89C = -40.0f;
intro_eye_counter = 0;
virtualaddress = address;
romCopy(virtualaddress, &_rarewarelogoSegmentRomStart, ALIGN64_V2((u32)&_rarewarelogoSegmentEnd - (u32)&_rarewarelogoSegmentStart));
romCopy(PORT_N64PTR(void, virtualaddress), &_rarewarelogoSegmentRomStart, ALIGN64_V2((u32)&_rarewarelogoSegmentEnd - (u32)&_rarewarelogoSegmentStart));
}
@@ -416,7 +420,7 @@ Gfx *retrieve_display_rareware_logo(Gfx *gdl)
#endif
D_8002A7D0 = (1 - D_8002A7D0);
gSPSegment(gdl++, SPSEGMENT_GETITLE, osVirtualToPhysical(virtualaddress));
gSPSegment(gdl++, SPSEGMENT_GETITLE, osVirtualToPhysical(PORT_N64PTR(void, virtualaddress)));
if ((gunbarrel_mode == 0) || (gunbarrel_mode == 1)) {
s32 var1;
s32 var2;
@@ -461,8 +465,8 @@ void sub_GAME_7F008DE4(u8 **addr, s32 *size) {
*size -= 0x40400;
*addr += 0x40400;
dword_CODE_bss_80069588 = *addr;
romCopy(dword_CODE_bss_80069588, (void *)(s32)&unknown2, ALIGN64_V2(((u32)&unknown2_end - (u32)&unknown2)));
rle_expand_8bit(dword_CODE_bss_80069588, dword_CODE_bss_8006958C);
romCopy(PORT_N64PTR(void, dword_CODE_bss_80069588), PORT_N64PTR(void, &unknown2), ALIGN64_V2(((u32)&unknown2_end - (u32)&unknown2)));
rle_expand_8bit(PORT_N64PTR(u8, dword_CODE_bss_80069588), PORT_N64PTR(u8, dword_CODE_bss_8006958C));
}
@@ -487,7 +491,7 @@ void initializeGunBarrelIntro(u8 *gfxBuffer, s32 bufferSize)
bufferSize -= 0x200;
gfxBuffer += 0x200;
createGunbarrelRenderHole(barrelDisplayListPtr, 0x1E);
createGunbarrelRenderHole(PORT_N64PTR(struct s_display_list_something, barrelDisplayListPtr), 0x1E);
gunbarrelgfxListPointer = (Gfx*)gfxBuffer;
#ifdef PORT
@@ -517,7 +521,7 @@ void initializeGunBarrelIntro(u8 *gfxBuffer, s32 bufferSize)
* N64 K0 value from the physical offset; seg_addr() passes it through to
* the KSEG0 mirror at 0x80000000 (segments 7/8 are never registered, so
* the unmarked-segment path is skipped). */
sub_GAME_7F01BFF8(gunbarrelgfxListPointer, (Vtx *)(OS_K0_TO_PHYSICAL((void *)barrelDisplayListPtr) | 0x80000000u), 0x1E);
sub_GAME_7F01BFF8(gunbarrelgfxListPointer, (Vtx *)(OS_K0_TO_PHYSICAL((void *)portN64ToHost((u32)barrelDisplayListPtr)) | 0x80000000u), 0x1E);
#else
sub_GAME_7F01BFF8(gunbarrelgfxListPointer, barrelDisplayListPtr + 0x80000000, 0x1E);
#endif
@@ -559,7 +563,7 @@ void initializeGunBarrelIntro(u8 *gfxBuffer, s32 bufferSize)
modelSetAnimPlaySpeed(chrModelInstance, S_7F008E80_ANIM_SPEED, 0.0f);
#undef S_7F008E80_ANIM_SPEED
animation = (struct ModelAnimation*)((s32)ptr_animation_table + (s32)&ANIM_DATA_bond_eye_walk);
animation = PORT_N64PTR(struct ModelAnimation, (s32)ptr_animation_table + (s32)&ANIM_DATA_bond_eye_walk);
startframe = animation->unk04 - 0x44;
while (startframe < 0)
{
+1 -1
View File
@@ -49,7 +49,7 @@ void alCSeqNew(ALCSeq *seq, u8 *ptr)
{
flagTmp = 1 << i;
seq->validTracks |= flagTmp;
seq->curLoc[i] = (u8*)((u32)ptr + tmpOff);
seq->curLoc[i] = (u8*)((uintptr_t)ptr + tmpOff);
seq->evtDeltaTicks[i] = __readVarLen(seq,i);
/*__alCSeqGetTrackEvent(seq,i); prime the event buffers */
}
+4 -4
View File
@@ -23,7 +23,7 @@
#include "synthInternals.h"
#include <os.h>
#include <R4300.h>
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#include <stdio.h>
#include <stdlib.h>
#include "audiotrace.h" /* D202/M-70: serialized trace writer */
@@ -200,7 +200,7 @@ Acmd *alAdpcmPull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset, Acmd
f->memin += ADPCMFBYTES*nframes;
}
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
/* D202/M-65 diag (temporary): a wave with no ALADPCMloop must run out and
* be zero-filled (nOver > 0) once memin passes base+len. If a voice keeps
* decoding past that point, an unstopped voice stays audible forever
@@ -393,7 +393,7 @@ alLoadParam(void *filter, s32 paramID, void *param)
switch (paramID) {
case (AL_FILTER_SET_WAVETABLE):
a->table = (ALWaveTable *) param;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
if (GE_ENVFLAG("GE_AUDIOTRACE")) {
extern uint64_t sysGetMicroseconds(void); /* port/src/system.c */
geTracePrintf("audiotrace_wire.log", "[WIRE] t=%llu filter=%p <- table=%p base=%p len=%d book=%p\n",
@@ -496,7 +496,7 @@ Acmd *_decodeChunk(Acmd *ptr, ALLoadFilter *f, s32 tsam, s32 nbytes, s16 outp, s
dramLoc;
if (nbytes > 0){
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
if (GE_ENVFLAG("GE_MIXERTRACE")) {
static FILE *dtf = NULL;
if (!dtf) { dtf = fopen("mixertrace.log", "a"); if (dtf) setvbuf(dtf, NULL, _IONBF, 0); }
+1 -1
View File
@@ -21,7 +21,7 @@
#include <libaudio.h>
#include "synthInternals.h"
#include <os.h>
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#endif
#include "include/assert.h"
+1 -1
View File
@@ -19,7 +19,7 @@
*====================================================================*/
#include "synthInternals.h"
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#endif
#include <os_internal.h>
#include <ultraerror.h>
+1 -1
View File
@@ -19,7 +19,7 @@
*====================================================================*/
#include "synthInternals.h"
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#endif
#include <os_internal.h>
#include <ultraerror.h>
+1 -1
View File
@@ -19,7 +19,7 @@
*====================================================================*/
#include "synthInternals.h"
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#endif
#include <os_internal.h>
#include <ultraerror.h>
+2 -2
View File
@@ -20,7 +20,7 @@
#include "synthInternals.h"
#include "include/assert.h"
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#include <stdio.h>
#include <stdlib.h>
#endif
@@ -122,7 +122,7 @@ void alSynNew(ALSynth *drvr, ALSynConfig *c)
pv->channelKnob = (ALFilter *)&pv->envmixer;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
/* D202/M-69 diag (temporary): GE_AUDIOTRACE=1 logs the full
* PVoice -> decoder/resampler/env-state address map at synth init,
* so offline voicedump slot addresses can be tied to WIRE filter
+9
View File
@@ -1,4 +1,7 @@
#include <ultra64.h>
#if defined(PORT)
#include "port_addr.h" /* D298/M2: memaAlloc returns a DRAM address */
#endif
#include "mema.h"
#include "deb.h"
@@ -314,7 +317,13 @@ void *memaAlloc(u32 amount) {
best->addr = 0;
}
#if defined(PORT)
/* D298/M2: best->addr is an N64 DRAM address; hand back a live pointer.
* Identity at PORT_ADDR_BASE == 0. */
return portN64ToHost((u32)addr);
#else
return (void*)addr;
#endif
}
// Find the memaspace of the given address and reduce its size by the given
+39 -3
View File
@@ -2,6 +2,9 @@
#include <deb.h>
#include "memp.h"
#include "game/language.h"
#if defined(PORT)
#include "port_addr.h" /* portN64ToHost: DRAM window base (M2/D298) */
#endif
/**
* EU .data, offset from start of data_seg : 0x3640
@@ -43,8 +46,18 @@ void mempCheckMemflagTokens(s32 poolAreaStart, s32 poolAreaSize)
//set pool 0 to what boss wants (room_model_buffer)
//pool 0 = TotalPoolArea
#if defined(PORT)
/* D298/M2: the pool lives in the N64 DRAM window, which on macOS is
* shifted up by PORT_ADDR_BASE. boss.c passes N64 addresses (the pool
* must stay s32 for mempCheckMemflagTokens' arithmetic), so convert to
* host pointers here — the MemoryPool fields are u8*. Identity at
* PORT_ADDR_BASE == 0. The N64 build keeps the original line. */
g_mempPools[MEMPOOL_TOTAL].start = (u8 *)portN64ToHost((u32)poolAreaStart);
g_mempPools[MEMPOOL_TOTAL].end = g_mempPools[MEMPOOL_TOTAL].start + poolAreaSize;
#else
g_mempPools[MEMPOOL_TOTAL].start = poolAreaStart;
g_mempPools[MEMPOOL_TOTAL].end = poolAreaStart + poolAreaSize;
#endif
poolSizes = sdefaultmvals;
@@ -63,7 +76,7 @@ void mempCheckMemflagTokens(s32 poolAreaStart, s32 poolAreaSize)
if (poolSizes.me == 0)
{
poolSizes.mf = 0;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
/* D36 (PC port): the PERMANENT bank must also hold the enlarged
* music heap (MUSIC_ALLOCATION_BYTES in src/music.c, 0x2E000 ->
* 0x32000 on x86-64 due to libaudio pointer bloat). Grow the bank on
@@ -91,7 +104,6 @@ void mempSetBankStarts(s32 poolSizes[MEMPOOL_COUNT+1])
s32 bankstarts[MEMPOOL_COUNT] = {0};
s32 mempLen;
s32 mempRequested;
s32 mempStart;
//set MF, ML, ME first
i = 0;
@@ -130,13 +142,27 @@ void mempSetBankStarts(s32 poolSizes[MEMPOOL_COUNT+1])
// {0,0,0,0,poolAreaSize - 303104, poolAreaSize - 303104, poolAreaSize}
mempStart = g_mempPools[MEMPOOL_TOTAL].start;
#if defined(PORT)
{
uintptr_t mempStart = (uintptr_t)g_mempPools[MEMPOOL_TOTAL].start;
#else
{
s32 mempStart = g_mempPools[MEMPOOL_TOTAL].start;
#endif
//for each bank 1-7, add new start position
for (i = MEMPOOL_TOTAL; i < MEMPOOL_COUNT - 1; i++)
{
#if defined(PORT)
/* D298/M2: pool fields are u8* host pointers in the DRAM window. */
g_mempPools[i + 1].start = (u8 *)(mempStart + bankstarts[i]);
g_mempPools[i + 1].pos = 0;
g_mempPools[i + 1].end = (u8 *)(mempStart + bankstarts[i + 1]);
#else
g_mempPools[i + 1].start = bankstarts[i] + mempStart;
g_mempPools[i + 1].pos = 0;
g_mempPools[i + 1].end = bankstarts[i + 1] + mempStart;
#endif
}
}
/*
rel-start size
@@ -201,6 +227,12 @@ void *mempAllocBytesInBank(u32 bytes, u8 poolnum)
nulled_mempLoopAllMemBanks();
#if defined(PORT)
osSyncPrintf("memp OOM: bank=%d bytes=0x%X left=0x%X pos=%p end=%p\n",
(int)poolnum, (unsigned)bytes,
(unsigned)(uintptr_t)(pool->end - pool->pos),
(void *)pool->pos, (void *)pool->end);
#endif
while (1);
}
@@ -237,6 +269,10 @@ MEMP_ADD_ENTRY_RESULT mempAddEntryOfSizeToBank(void *allocation, s32 newsize, u8
if (allocation != pool->prevpos)
{
#if defined(PORT)
osSyncPrintf("mempAddEntry: NOT_LAST bank=%d alloc=%p prevpos=%p\n",
(int)poolnum, allocation, (void *)pool->prevpos);
#endif
return MEMP_ADD_ENTRY_NOT_LAST_ALLOCATION;
}
+6 -6
View File
@@ -52,7 +52,7 @@
* allocated later from this heap need N64-equivalent headroom on top, so
* budget 0x38000 (init headroom ~19 KiB). PC only.
*/
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
#define MUSIC_ALLOCATION_BYTES 0x38000
#else
#define MUSIC_ALLOCATION_BYTES 0x2E000
@@ -685,7 +685,7 @@ void musicSeqPlayerInit(void)
{
size = (u32)&_sfxtblSegmentRomStart - (u32)&_sfxctlSegmentRomStart;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
// D37: the PC-native bank image is larger than the ROM segment
// (4-byte packed offsets become 8-byte pointer slots); allocate the
// re-laid-out size, copy only the ROM bytes, then convert.
@@ -708,7 +708,7 @@ void musicSeqPlayerInit(void)
{
size = (u32)&_instrumentstblSegmentRomStart - (u32)&_instrumentsctlSegmentRomStart;
#if defined(__x86_64__)
#if defined(PLATFORM_64BIT)
// D37: as above.
{
u32 romSize = size;
@@ -876,7 +876,7 @@ void musicTrack1Play(s32 track)
t3 = ALIGN16_a(g_musicTrackLength[g_musicXTrack1CurrentTrackNum]) + ALIGN16_a(NUM_MUSIC_TRACKS);
trackSizeBytes = ALIGN16_a(g_musicTrackCompressedLength[g_musicXTrack1CurrentTrackNum]);
thing.seqData = g_musicXTrack1SeqData;
temp_a0 = (u8*)((t3 + (s32)thing.seqData) - trackSizeBytes);
temp_a0 = (u8*)(((uintptr_t)thing.seqData + t3) - trackSizeBytes);
romCopy(temp_a0, romAddress, trackSizeBytes);
decompressdata(temp_a0, thing.seqData, &hlist);
@@ -1070,7 +1070,7 @@ void musicTrack2Play(s32 track)
t3 = ALIGN16_a(g_musicTrackLength[g_musicXTrack2CurrentTrackNum]) + ALIGN16_a(NUM_MUSIC_TRACKS);
trackSizeBytes = ALIGN16_a(g_musicTrackCompressedLength[g_musicXTrack2CurrentTrackNum]);
thing.seqData = g_musicXTrack2SeqData;
temp_a0 = (u8*)((t3 + (s32)thing.seqData) - trackSizeBytes);
temp_a0 = (u8*)(((uintptr_t)thing.seqData + t3) - trackSizeBytes);
romCopy(temp_a0, romAddress, trackSizeBytes);
decompressdata(temp_a0, thing.seqData, &hlist);
@@ -1263,7 +1263,7 @@ void musicTrack3Play(s32 track)
t3 = ALIGN16_a(g_musicTrackLength[g_musicXTrack3CurrentTrackNum]) + ALIGN16_a(NUM_MUSIC_TRACKS);
trackSizeBytes = ALIGN16_a(g_musicTrackCompressedLength[g_musicXTrack3CurrentTrackNum]);
thing.seqData = g_musicXTrack3SeqData;
temp_a0 = (u8*)((t3 + (s32)thing.seqData) - trackSizeBytes);
temp_a0 = (u8*)(((uintptr_t)thing.seqData + t3) - trackSizeBytes);
romCopy(temp_a0, romAddress, trackSizeBytes);
decompressdata(temp_a0, thing.seqData, &hlist);