Native iPhone port of Factorio 2.0.77
Run the original macOS ARM64 game code on iOS: - tools/retarget.py: header-only Mach-O retargeting to an iOS dylib - platform/native: UIKit host and macOS API shims (AppKit for SDL's Cocoa backend, CoreGraphics displays, CoreAudio device, Metal device properties, Wuffs PNG decoding, Steam and peripheral stubs) - touch, overlay, iOS keyboard and hardware keyboard input - tools/build_native.py: build, sign, install, data copy, launch - docs: build guide, controls, architecture Also includes the earlier static-translation research (ARM64 -> WASM -> native) under docs/research, runtime/, tests/ and tools/. No game files are included; the build reads them from a local install.
This commit is contained in:
commit
51d085e865
89 files changed
+7999
No files matched your search
@@ -0,0 +1,100 @@
|
||||
"""Native comparisons for the instruction forms added for allocation/initialization."""
|
||||
import json
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0,str(ROOT/'tools'))
|
||||
from a64_program import ProgramCompiler
|
||||
from a64_lift import UnsupportedInstruction
|
||||
OUT=ROOT/'build/initialization'
|
||||
OUT.mkdir(parents=True,exist_ok=True)
|
||||
def pack(words): return struct.pack('<'+'I'*len(words),*words)
|
||||
def run(*args): subprocess.run(list(map(str,args)),cwd=ROOT,check=True)
|
||||
|
||||
operations=[]
|
||||
for width in (32,64):
|
||||
for shift in range(width):
|
||||
operations.append((0x13000000 if width==32 else 0x93400000) | shift<<16 | (width-1)<<10)
|
||||
for length in range(1,6 if width==32 else 7):
|
||||
for operation in range(3):
|
||||
# Rotate repeated patterns at every supported element size.
|
||||
n=int(length==6)
|
||||
s=((((~((1 << (length+1))-1))&63) | ((1 << length)//2-1)))
|
||||
rotation=(1 << length)-1
|
||||
operations.append((0x12000000 if width==32 else 0x92000000) | operation<<29 | n<<22 | rotation<<16 | s<<10)
|
||||
words=[]
|
||||
for word in operations:
|
||||
words += [0xaa0203e0,word,0xf8008420] # mov x0,x2; op; str x0,[x1],#8
|
||||
words += [0xd65f03c0]
|
||||
compiler=ProgramCompiler(memory_pages=2)
|
||||
(OUT/'initialization.wat').write_text(compiler.compile({0x1000:pack(words)},0x1000))
|
||||
run(ROOT/'build/wabt/wat2wasm',OUT/'initialization.wat','-o',OUT/'initialization.wasm')
|
||||
run(ROOT/'build/wabt/wasm2c',OUT/'initialization.wasm','-o',OUT/'initialization.c','--module-name=initialization')
|
||||
(OUT/'oracle.S').write_text('.text\n.p2align 2\n.globl _native_initialization\n_native_initialization:\n'+
|
||||
'\n'.join(f'.long 0x{w:08x}' for w in words)+'\n')
|
||||
invalid=[
|
||||
[0x3c800000,0xd65f03c0], # uninitialized vector register
|
||||
[0xb4000040,0x6f00e400,0x3c800000,0xd65f03c0], # zero is missing on one incoming path
|
||||
[0x14000002,0x6f00e400,0x3c800000,0xd65f03c0], # branch into the idiom
|
||||
[0x6f00e400,0x3c800001,0xd65f03c0], # mismatched vector register
|
||||
[0x90000000,0xd65f03c0], # undeclared static page
|
||||
[0x9240fc00,0xd65f03c0], # reserved all-ones logical mask
|
||||
[0x93400000,0xd65f03c0], # signed bitfield beyond ASR
|
||||
]
|
||||
for fixture in invalid:
|
||||
try: ProgramCompiler().compile({0x1000:pack(fixture)},0x1000)
|
||||
except UnsupportedInstruction: pass
|
||||
else: raise AssertionError('Invalid initialization fixture accepted')
|
||||
for options in [dict(memory_pages=0),dict(memory_pages=32769),dict(returning_hosts={1}),
|
||||
dict(static_pages={0:1}),dict(hosts={1:'same',2:'same'},returning_hosts={1})]:
|
||||
try: ProgramCompiler(**options)
|
||||
except ValueError: pass
|
||||
else: raise AssertionError('Invalid program configuration accepted')
|
||||
(OUT/'verify.c').write_text(f'''
|
||||
#include "initialization.h"
|
||||
#include "wasm-rt-impl.h"
|
||||
#include "wasm-rt-exceptions.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
extern uint64_t native_initialization(uint64_t,uint64_t *,uint64_t);
|
||||
int main(void) {{
|
||||
wasm_rt_init();w2c_initialization module;wasm2c_initialization_instantiate(&module);
|
||||
uint8_t *memory=w2c_initialization_memory(&module)->data;
|
||||
uint64_t seed=0xdeadbeef12345678,reference[{len(operations)}];
|
||||
for(unsigned i=0;i<512;++i) {{
|
||||
seed^=seed<<13;seed^=seed>>7;seed^=seed<<17;
|
||||
uint64_t input=i==0 ? 0 : i==1 ? UINT64_MAX : seed;
|
||||
uint64_t registers[32]={{0}};registers[1]=66048;registers[2]=input;
|
||||
memset(memory,0xa5,131072);memcpy(memory,registers,sizeof(registers));
|
||||
native_initialization(0,reference,input);
|
||||
assert(w2c_initialization_run(&module,0,10000)==0);
|
||||
assert(memcmp(memory+66048,reference,sizeof(reference))==0);
|
||||
for(unsigned j=256;j<131072;++j) {{
|
||||
if(j>=66048 && j<66048+sizeof(reference)) continue;
|
||||
assert(memory[j]==0xa5);
|
||||
}}
|
||||
}}
|
||||
const uint64_t bad[]={{131072-7,131072,UINT64_C(0x100000000)+66048,UINT64_MAX-7}};
|
||||
for(unsigned i=0;i<sizeof(bad)/sizeof(bad[0]);++i) {{
|
||||
uint64_t registers[32]={{0}};registers[1]=bad[i];
|
||||
memset(memory,0xa5,131072);memcpy(memory,registers,sizeof(registers));
|
||||
wasm_rt_trap_t trap=wasm_rt_impl_try();
|
||||
if(!trap) {{w2c_initialization_run(&module,0,10000);assert(0);}}
|
||||
assert(trap==WASM_RT_TRAP_UNREACHABLE);
|
||||
for(unsigned j=256;j<131072;++j) assert(memory[j]==0xa5);
|
||||
}}
|
||||
wasm2c_initialization_free(&module);wasm_rt_free();
|
||||
puts("PASS: {len(operations)*512} native ASR/logical-mask comparisons, extended memory, 64-bit address guards, 12 rejection cases");
|
||||
}}
|
||||
''')
|
||||
runtime=ROOT/'third_party/wabt/wasm2c'
|
||||
run('xcrun','clang','-O2','-DWASM_RT_USE_MMAP=0','-DWASM_RT_MEMCHECK_BOUNDS_CHECK=1',
|
||||
'-I'+str(OUT),'-I'+str(runtime),OUT/'initialization.c',OUT/'verify.c',OUT/'oracle.S',
|
||||
runtime/'wasm-rt-impl.c',runtime/'wasm-rt-mem-impl.c',runtime/'wasm-rt-exceptions-impl.c','-o',OUT/'verify')
|
||||
run(OUT/'verify')
|
||||
(OUT/'verification.json').write_text(json.dumps({'status':'pass','native_comparisons':len(operations)*512,
|
||||
'instruction_forms':len(operations),'invalid_cases':12,'source':'hand-authored instruction fixtures'},indent=2)+'\n')
|
||||
Reference in new issue
Block a user