qvm: pre-firing return chains
Browse files- docs/ASSET_PIPELINE_TODO.md +3 -0
- docs/FINDINGS.md +3 -0
- docs/PROVISIONAL_TODO.md +5 -0
- docs/RESEARCH_LEDGER.md +7 -0
- docs/REVERSE_ENGINEERING_TODO.md +7 -1
- docs/research/QVM_CONSUMER_BATCH.md +2 -0
- docs/research/QVM_WEAPON_BATCH.md +48 -0
- docs/research/QVM_WEAPON_RETURN_CHAINS.md +11 -0
- docs/research/README.md +5 -0
- docs/research/qvm-weapon-return-chains.json +0 -0
- scripts/analyze_qvm_main_consumers.py +3 -2
- scripts/analyze_qvm_weapon_ready.py +5 -3
- scripts/analyze_qvm_weapon_return_chains.py +44 -0
- scripts/test_qvm_weapon_return_chains.py +49 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -427,3 +427,6 @@ Research progress: RE-578 [report](research/QVM_RELOAD_COMPLETE.md); remaining n
|
|
| 427 |
|
| 428 |
|
| 429 |
Research progress: RE-579 [report](research/QVM_WEAPON_PHASES.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
|
| 428 |
|
| 429 |
Research progress: RE-579 [report](research/QVM_WEAPON_PHASES.md); remaining native/content/runtime/platform scope stays open.
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
Research progress: RE-580 [report](research/QVM_WEAPON_RETURN_CHAINS.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -785,3 +785,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 785 |
|
| 786 |
|
| 787 |
**RE-579 — Weapon lowering raising and frame gates:** 51633..51801 completes state2 via49028, resets state1 to0 and selects a separate class-based torso table, then gates other states on FRAME232 and FRAME36 before firing entry51802. [Evidence](research/QVM_WEAPON_PHASES.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 785 |
|
| 786 |
|
| 787 |
**RE-579 — Weapon lowering raising and frame gates:** 51633..51801 completes state2 via49028, resets state1 to0 and selects a separate class-based torso table, then gates other states on FRAME232 and FRAME36 before firing entry51802. [Evidence](research/QVM_WEAPON_PHASES.md).
|
| 788 |
+
|
| 789 |
+
|
| 790 |
+
**RE-580 — Pre-firing weapon return chains and actual main suffix handoff:** Recovered50746 branches now compose through51801, preserving the pre-switch mode local; actual53046 returns resume main torso/locomotion/water calls while51802 paths keep the caller suspended. [Evidence](research/QVM_WEAPON_RETURN_CHAINS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -741,3 +741,8 @@ Research progress: RE-578 [report](research/QVM_RELOAD_COMPLETE.md); remaining n
|
|
| 741 |
|
| 742 |
|
| 743 |
Research progress: RE-579 [report](research/QVM_WEAPON_PHASES.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 741 |
|
| 742 |
|
| 743 |
Research progress: RE-579 [report](research/QVM_WEAPON_PHASES.md); remaining native/content/runtime/platform scope stays open.
|
| 744 |
+
|
| 745 |
+
The [RE-571–580 weapon batch](research/QVM_WEAPON_BATCH.md) closes bounded lookup, selection/completion, helper50525 and pre-firing return branches. Its next ten tasks prioritize51802+ firing/availability and complete main/reference validation. Rust/Bevy/Solari macOS/Linux runtime, native/content/rendering and whole-game scope remain open.
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
Research progress: RE-580 [report](research/QVM_WEAPON_RETURN_CHAINS.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -591,3 +591,10 @@ Actual54444 reload/interaction order exposes timer interference before the weapo
|
|
| 591 |
## 2026-10-20 — RE-579 Weapon lowering raising and frame gates (separate task commit)
|
| 592 |
|
| 593 |
51633..51801 completes state2 via49028, resets state1 to0 and selects a separate class-based torso table, then gates other states on FRAME232 and FRAME36 before firing entry51802. 87 fixtures independently check completion fallback and state handoff, all classes−1..8, button priority, animation timer/type guards and both frame gates. Full suite: 835 tests pass. Report regenerates byte-identically (796730 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 591 |
## 2026-10-20 — RE-579 Weapon lowering raising and frame gates (separate task commit)
|
| 592 |
|
| 593 |
51633..51801 completes state2 via49028, resets state1 to0 and selects a separate class-based torso table, then gates other states on FRAME232 and FRAME36 before firing entry51802. 87 fixtures independently check completion fallback and state handoff, all classes−1..8, button priority, animation timer/type guards and both frame gates. Full suite: 835 tests pass. Report regenerates byte-identically (796730 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
## 2026-10-20 — RE-580 Pre-firing weapon return chains and actual main suffix handoff (separate task commit)
|
| 597 |
+
|
| 598 |
+
Recovered50746 branches now compose through51801, preserving the pre-switch mode local; actual53046 returns resume main torso/locomotion/water calls while51802 paths keep the caller suspended. 16 independent source-order scenarios check every reload/interaction/prefix/selection/guard/ready/ammo/phase handoff, full final state, suspension versus resume and old-mode-local preservation. Full suite: 839 tests pass. Report regenerates byte-identically (1198369 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 599 |
+
|
| 600 |
+
RE-580 additional regression: all19 reports from RE-560–569 and RE-571–579 regenerate byte-identically after the explicit-byte-input and optional caller-memory/local-preservation additions. The new composition keeps the parent suspended at51802 rather than assuming a firing-body return.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -750,7 +750,7 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 750 |
|
| 751 |
- [x] RE-568 Complete locomotion gait bob and footstep consumer ([report](research/QVM_LOCOMOTION.md)).
|
| 752 |
|
| 753 |
-
- [ ] RE-570
|
| 754 |
|
| 755 |
|
| 756 |
- [x] RE-569 Main request and independently bounded animation consumer chains ([report](research/QVM_MAIN_CONSUMERS.md)).
|
|
@@ -781,3 +781,9 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 781 |
|
| 782 |
|
| 783 |
- [x] RE-579 Weapon lowering raising and frame gates ([report](research/QVM_WEAPON_PHASES.md)).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 750 |
|
| 751 |
- [x] RE-568 Complete locomotion gait bob and footstep consumer ([report](research/QVM_LOCOMOTION.md)).
|
| 752 |
|
| 753 |
+
- [ ] RE-570 Partially closed by RE-571–580:48798/49028 selection/completion,50525 and pre-firing continuation through51801 are recovered. Remaining51802..53045 firing/availability, resource writers, main final vector snap, original reference ticks, asset-ID mapping and Rust/Bevy/Solari macOS/Linux runtime stay open. See [weapon batch](research/QVM_WEAPON_BATCH.md).
|
| 754 |
|
| 755 |
|
| 756 |
- [x] RE-569 Main request and independently bounded animation consumer chains ([report](research/QVM_MAIN_CONSUMERS.md)).
|
|
|
|
| 781 |
|
| 782 |
|
| 783 |
- [x] RE-579 Weapon lowering raising and frame gates ([report](research/QVM_WEAPON_PHASES.md)).
|
| 784 |
+
|
| 785 |
+
|
| 786 |
+
- [ ] RE-581 Recover51802+ charge/hold/release, availability failure, ammunition decrement and remaining firing children; finish50746 and main final native snap before full-tick composition. Validate legal multi-tick behavior against original execution and continue full native/content/rendering/platform implementation. See the [next ten tasks](research/QVM_WEAPON_BATCH.md#next-ten-concrete-tasks).
|
| 787 |
+
|
| 788 |
+
|
| 789 |
+
- [x] RE-580 Pre-firing weapon return chains and actual main suffix handoff ([report](research/QVM_WEAPON_RETURN_CHAINS.md)).
|
docs/research/QVM_CONSUMER_BATCH.md
CHANGED
|
@@ -44,3 +44,5 @@ RE-569 does **not** complete a main tick. It evaluates54444..54451 (reload and i
|
|
| 44 |
8. Map numeric animation and event IDs to actual skeletal/audio assets, preserving variants and provenance.
|
| 45 |
9. Continue native/DLL/network/protocol/rendering/material and whole-content coverage from the broader todo-list.
|
| 46 |
10. Establish the first Rust/Bevy/Solari runtime slice and macOS/Linux validation; these bounded research tasks do not count as a playable game or platform completion.
|
|
|
|
|
|
|
|
|
| 44 |
8. Map numeric animation and event IDs to actual skeletal/audio assets, preserving variants and provenance.
|
| 45 |
9. Continue native/DLL/network/protocol/rendering/material and whole-content coverage from the broader todo-list.
|
| 46 |
10. Establish the first Rust/Bevy/Solari runtime slice and macOS/Linux validation; these bounded research tasks do not count as a playable game or platform completion.
|
| 47 |
+
|
| 48 |
+
The subsequent [RE-571–580 weapon batch](QVM_WEAPON_BATCH.md) recovers selection/completion and pre-firing continuation through51801, including actual early-return main handoffs. The missing-body boundary above describes this earlier batch; the new report records the narrower remaining51802+ scope.
|
docs/research/QVM_WEAPON_BATCH.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Weapon-state research batch: RE-571–580
|
| 2 |
+
|
| 3 |
+
Ten separately committed tasks extend the previous [consumer batch](QVM_CONSUMER_BATCH.md). They recover weapon lookup, selection, transition completion, a native-query contract and the pre-firing50746 branches through51801. Source identity, bounded instruction traces, independent state oracles and synthetic/native response limits accompany each report.
|
| 4 |
+
|
| 5 |
+
| Task | Recovered scope | Evidence |
|
| 6 |
+
| --- | --- | --- |
|
| 7 |
+
| RE-571 | Complete31691 first16-slot weapon lookup | [Lookup](QVM_WEAPON_LOOKUP.md) |
|
| 8 |
+
| RE-572 | Complete48798 selection request and transition effects | [Selection](QVM_WEAPON_SELECT.md) |
|
| 9 |
+
| RE-573 | Complete49028 selected/fallback lookup and raising transition | [Completion](QVM_WEAPON_COMPLETE.md) |
|
| 10 |
+
| RE-574 | Complete50525 ordered input gates and native trace/event contract | [Special query](QVM_SPECIAL_QUERY.md) |
|
| 11 |
+
| RE-575 | Actual50746 prefix through selection handoff50922 | [Caller](QVM_WEAPON_SELECTION_CALLER.md) |
|
| 12 |
+
| RE-576 |50923..51206 guards, timer floors and state512 cancellation | [Guards](QVM_WEAPON_GUARDS.md) |
|
| 13 |
+
| RE-577 |51207..51364 ID27 refill, cadence and interaction re-entry | [Ready consumer](QVM_WEAPON_READY.md) |
|
| 14 |
+
| RE-578 |51365..51632 ammo transfer and actual reload re-entry | [Reload completion](QVM_RELOAD_COMPLETE.md) |
|
| 15 |
+
| RE-579 |51633..51801 lowering/raising completion and frame gates | [Phases](QVM_WEAPON_PHASES.md) |
|
| 16 |
+
| RE-580 | Source-ordered pre-firing weapon paths and main suffix resumed only after actual return | [Return chains](QVM_WEAPON_RETURN_CHAINS.md) |
|
| 17 |
+
|
| 18 |
+
## Findings that affect the port
|
| 19 |
+
|
| 20 |
+
- Weapon lookup and item lookup use different16-slot arrays, at PS312 and PS376 respectively. Weapon records match low-byte ID to the full requested argument.
|
| 21 |
+
- Selection starts state2 and does not change the active slot. Completion changes the slot, sets state1 and adds250 to the timer. Missing command ID falls back to1; a missing fallback is not checked before storing−1. Checked Rust handling requires an explicit policy backed by runtime evidence.
|
| 22 |
+
- Two continuation guards literally assign localID12 on fallback branches. The shipped instruction behavior is documented without guessing intended C logic.
|
| 23 |
+
- Incremental reload adds one modulo256 to the magazine; replacement reload writes configured capacity. Both subtract one modulo256 from reserve. The reserve unit is not established by that arithmetic alone.
|
| 24 |
+
- Reload completion clears its flag before calling reload request with argument0. Held input can restart a reload under the actual child gates, without the extra reload timer component.
|
| 25 |
+
- Phase completion uses a different torso table from idle selection: class4 always requests72 here, with no tag22 exception.
|
| 26 |
+
- The parent keeps the mode local decoded before49327 even if packed mode changes afterward. Composition must preserve the local instead of reconstructing it from the new packed word. An explicitly supplied zero switch timer lets a fixture reach this otherwise gated boundary.
|
| 27 |
+
- Helper50525 consumes trace reply contents+48 and event parameter+52, but native geometry and the gameplay identity of that parameter remain unverified.
|
| 28 |
+
|
| 29 |
+
## Integration boundary
|
| 30 |
+
|
| 31 |
+
RE-580 executes54444..54451 reload/interaction, then composes50747..51801 in the same parent local frame. Paths reaching the actual void epilogue53046 can resume54455..54463 torso/locomotion/water consumers. Paths reaching51802 keep the parent suspended. This replaces the previous blanket weapon-prefix gap for the recovered return paths; it does not invent a return from the still-unrecovered firing body.
|
| 32 |
+
|
| 33 |
+
The void epilogue/parent POP are explicit source boundary bridges; this is not a full VM interpreter. Earlier main setup, clock, timer, movement and environment effects are supplied rather than composed here. The final native vector snap54471 is omitted. Successive standalone calls are not claimed as complete game ticks. Native trace records and animation durations remain supplied fixtures. No original game executable or native library runs, and no Rust gameplay/rendering/platform work is counted as completed by this batch.
|
| 34 |
+
|
| 35 |
+
The baseline799 tests gains40 independent checks. Every report is reproducible below the2MiB normal-Git cap. The asset filters remain in force and originals remain outside normal Git.
|
| 36 |
+
|
| 37 |
+
## Next ten concrete tasks
|
| 38 |
+
|
| 39 |
+
1. Recover51802..52084 mode-flag8 charge/hold/release and cancellation, including50309 availability handoff and requested-weapon exceptions.
|
| 40 |
+
2. Recover52085..52153 state/availability failure, ID27 exception, event29 and timer+500.
|
| 41 |
+
3. Recover52154+ ammunition decrement and mode-flag4 exception, retaining packed ID/mode/reserve and byte boundaries.
|
| 42 |
+
4. Partition the remaining52253..53045 firing branches by return/callee boundaries and inventory every child/native request before interpreting them.
|
| 43 |
+
5. Recover mode delays, burst counters and state writes after firing without presuming projectile/hitscan outcomes.
|
| 44 |
+
6. Recover remaining firing-event parameters, recoil/spread/aim effects and native ABI consumers; compare legal configuration writers with initialized image records.
|
| 45 |
+
7. Compose complete50746 calls only when all reached firing children are recovered; add real multi-tick selection/reload/firing scenarios with actual timer/environment consumers.
|
| 46 |
+
8. Recover final main native vector snapping54471 and compose the complete main tick, preserving byte inputs, locals and all event/animation order.
|
| 47 |
+
9. Capture original-execution references and collision-consistent responses; map numeric weapon/animation/event identities to actual assets and validate legal input domains.
|
| 48 |
+
10. Continue the broader native/DLL/protocol/rendering/content work and first Rust/Bevy/Solari runtime slice on macOS/Linux. Bounded research coverage is not playable-game completion.
|
docs/research/QVM_WEAPON_RETURN_CHAINS.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pre-firing weapon return chains and actual main suffix handoff
|
| 2 |
+
|
| 3 |
+
RE-580. Reproduce with `python3 scripts/analyze_qvm_weapon_return_chains.py`; check with `python3 scripts/test_qvm_weapon_return_chains.py`. The [machine report](qvm-weapon-return-chains.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
The pre-firing composer starts with actual50747 prefix/selection, then carries the same parent locals through50923 guards,51207 ready handling,51365 reload completion and51633 phase completion. It stops only at51802 or the actual void epilogue53046. Ready handling can opt into preserving existing locals; defaults for standalone reports remain unchanged. A synthetic zero switch timer fixture proves that local mode1 survives when packed mode becomes0. Reconstructing locals from packed state would change source behavior.
|
| 6 |
+
|
| 7 |
+
Actual main54444..54451 first runs reload(argument1) and interaction. Its resulting state feeds this weapon composer. Only proven53046 returns bridge the source void epilogue/POP and resume54455..54463 torso/locomotion/water consumers. Paths reaching51802 do not resume.16 scenarios cover lowering wait/completion, raising, reload and held reload, action re-entry, early flags/death, frame gate, ID27, mode switching and a new selection request. Exact state is compared at every child and stage boundary.
|
| 8 |
+
|
| 9 |
+
The earlier animation-chain helper now optionally returns its memory for actual handoff; default reports are unchanged. This is still a bounded staged interpretation: no51802..53045 firing body, final native snap54471, earlier main setup/clock/timer/environment/movement or original execution is composed. Therefore no full tick/gameplay claim is made. See the [ten-task batch and next work](QVM_WEAPON_BATCH.md).
|
| 10 |
+
|
| 11 |
+
No original executable/full QVM/native collision/physics/rendering executes. Native responses and legal input domains are supplied or unverified where stated; full runtime/macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
docs/research/README.md
CHANGED
|
@@ -342,3 +342,8 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 342 |
|
| 343 |
|
| 344 |
[RE-579: Weapon lowering raising and frame gates](QVM_WEAPON_PHASES.md). Reproduce with `python3 scripts/analyze_qvm_weapon_phases.py`; check with `python3 scripts/test_qvm_weapon_phases.py`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
|
| 343 |
|
| 344 |
[RE-579: Weapon lowering raising and frame gates](QVM_WEAPON_PHASES.md). Reproduce with `python3 scripts/analyze_qvm_weapon_phases.py`; check with `python3 scripts/test_qvm_weapon_phases.py`.
|
| 345 |
+
|
| 346 |
+
[RE-571–580 weapon batch and next ten tasks](QVM_WEAPON_BATCH.md): source-ordered transition/reload return paths and the explicit remaining firing/main boundary.
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
[RE-580: Pre-firing weapon return chains and actual main suffix handoff](QVM_WEAPON_RETURN_CHAINS.md). Reproduce with `python3 scripts/analyze_qvm_weapon_return_chains.py`; check with `python3 scripts/test_qvm_weapon_return_chains.py`.
|
docs/research/qvm-weapon-return-chains.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_main_consumers.py
CHANGED
|
@@ -23,13 +23,14 @@ def entry_chain(ins,m,contents,cmd=(0,0,0)):
|
|
| 23 |
m,w=weapon_prefix(ins,m,c)
|
| 24 |
return {'initial':initial,'main_execution':r,'before_weapon':before,'weapon_prefix':w,'final':state(m),'main_stopped_before':54452,'pending_call_instruction':54453,'parent_resumed':False}
|
| 25 |
|
| 26 |
-
def animation_chain(ins,m,cmd):
|
| 27 |
initial=state(m)
|
| 28 |
def child(fn):
|
| 29 |
def apply(i,m,a,c):m,r=fn(i,m,c);return m,c,0,r
|
| 30 |
return apply
|
| 31 |
m,c,r=execute(ins,54455,54464,m,cmd,LOCAL+0x1000,{49117:child(torso),47884:child(locomotion),48716:child(water_events)})
|
| 32 |
-
|
|
|
|
| 33 |
|
| 34 |
def main():
|
| 35 |
q,raw,h,ins=source();entries=[];animations=[]
|
|
|
|
| 23 |
m,w=weapon_prefix(ins,m,c)
|
| 24 |
return {'initial':initial,'main_execution':r,'before_weapon':before,'weapon_prefix':w,'final':state(m),'main_stopped_before':54452,'pending_call_instruction':54453,'parent_resumed':False}
|
| 25 |
|
| 26 |
+
def animation_chain(ins,m,cmd,return_memory=False):
|
| 27 |
initial=state(m)
|
| 28 |
def child(fn):
|
| 29 |
def apply(i,m,a,c):m,r=fn(i,m,c);return m,c,0,r
|
| 30 |
return apply
|
| 31 |
m,c,r=execute(ins,54455,54464,m,cmd,LOCAL+0x1000,{49117:child(torso),47884:child(locomotion),48716:child(water_events)})
|
| 32 |
+
report={'initial':initial,'supplied_post_weapon_state':True,'execution':r,'final':state(m),'stop_before':54464}
|
| 33 |
+
return (m,report) if return_memory else report
|
| 34 |
|
| 35 |
def main():
|
| 36 |
q,raw,h,ins=source();entries=[];animations=[]
|
scripts/analyze_qvm_weapon_ready.py
CHANGED
|
@@ -9,11 +9,13 @@ from analyze_qvm_interaction_request import interaction
|
|
| 9 |
from analyze_qvm_acceleration import PS,FRAME
|
| 10 |
from analyze_qvm import write_json
|
| 11 |
|
| 12 |
-
def ready(ins,m,cmd=(0,0,0),contents=33554432):
|
| 13 |
-
initial=weapon_state(m)
|
|
|
|
|
|
|
| 14 |
def action(i,m,a,c):m,r=interaction(i,m,contents,c);return m,c,0,r
|
| 15 |
m,c,r=execute(ins,51207,53046,m,cmd,LOCAL,{49918:action},boundaries=[51365])
|
| 16 |
-
return m,{'initial':initial,'buttons':m[FRAME+20],'config':cfg,'contents':contents,'execution':r,'final':weapon_state(m)}
|
| 17 |
|
| 18 |
def main():
|
| 19 |
q,raw,h,ins=source();rows=[]
|
|
|
|
| 9 |
from analyze_qvm_acceleration import PS,FRAME
|
| 10 |
from analyze_qvm import write_json
|
| 11 |
|
| 12 |
+
def ready(ins,m,cmd=(0,0,0),contents=33554432,preserve_locals=False):
|
| 13 |
+
initial=weapon_state(m)
|
| 14 |
+
if not preserve_locals:m[LOCAL+12]=initial['packed']&255;m[LOCAL+16]=(initial['packed']>>16)&255
|
| 15 |
+
ident=m[LOCAL+12];mode=m[LOCAL+16];cfg={'capacity':m[4052+432*ident],'mode_flags':m[4244+432*ident+52*mode+4]}
|
| 16 |
def action(i,m,a,c):m,r=interaction(i,m,contents,c);return m,c,0,r
|
| 17 |
m,c,r=execute(ins,51207,53046,m,cmd,LOCAL,{49918:action},boundaries=[51365])
|
| 18 |
+
return m,{**({'preserved_parent_locals':{'id':ident,'mode':mode}} if preserve_locals else {}),'initial':initial,'buttons':m[FRAME+20],'config':cfg,'contents':contents,'execution':r,'final':weapon_state(m)}
|
| 19 |
|
| 20 |
def main():
|
| 21 |
q,raw,h,ins=source();rows=[]
|
scripts/analyze_qvm_weapon_return_chains.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Source-ordered pre-fire weapon paths and main suffix only after real returns."""
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from qvm_research_support import source,execute
|
| 5 |
+
from qvm_weapon_support import weapon_seed,weapon_state
|
| 6 |
+
from analyze_qvm_weapon_selection_caller import selection_caller
|
| 7 |
+
from analyze_qvm_weapon_guards import guards
|
| 8 |
+
from analyze_qvm_weapon_ready import ready
|
| 9 |
+
from analyze_qvm_reload_complete import reload_complete
|
| 10 |
+
from analyze_qvm_weapon_phases import phases
|
| 11 |
+
from analyze_qvm_reload_request import reload
|
| 12 |
+
from analyze_qvm_interaction_request import interaction
|
| 13 |
+
from analyze_qvm_main_consumers import animation_chain
|
| 14 |
+
from analyze_qvm_acceleration import PS,FRAME
|
| 15 |
+
from analyze_qvm import write_json
|
| 16 |
+
LOCAL=0x77000000
|
| 17 |
+
|
| 18 |
+
def pre_fire(ins,m,cmd=(0,0,0),contents=33554432):
|
| 19 |
+
initial=weapon_state(m);m,r=selection_caller(ins,m,cmd);stages=[{'name':'selection','probe':r}];stop=r['stop']
|
| 20 |
+
for name,at,fn in [('guards',50923,guards),('ready',51207,lambda i,m,c:ready(i,m,c,contents,preserve_locals=True)),('reload',51365,reload_complete),('phases',51633,phases)]:
|
| 21 |
+
if stop!=at:break
|
| 22 |
+
m,r=fn(ins,m,cmd);stages.append({'name':name,'probe':r});stop=r['execution']['stop']
|
| 23 |
+
assert stop in [51802,53046]
|
| 24 |
+
return m,{'initial':initial,'stages':stages,'stop':stop,'returned':stop==53046,'final':weapon_state(m)}
|
| 25 |
+
|
| 26 |
+
def main_chain(ins,m,cmd=(0,0,0),contents=33554432):
|
| 27 |
+
initial=weapon_state(m)
|
| 28 |
+
def reload_child(i,m,a,c):m,r=reload(i,m,a[8],c);return m,c,0,r
|
| 29 |
+
def interaction_child(i,m,a,c):m,r=interaction(i,m,contents,c);return m,c,0,r
|
| 30 |
+
m,c,entry=execute(ins,54444,54452,m,cmd,LOCAL,{49652:reload_child,49918:interaction_child});before=weapon_state(m)
|
| 31 |
+
assert ins[54452]['operand']==50746 and ins[54453]['opcode']=='CALL'
|
| 32 |
+
m,w=pre_fire(ins,m,c,contents);tail=None
|
| 33 |
+
if w['returned']:
|
| 34 |
+
m,tail=animation_chain(ins,m,c,return_memory=True)
|
| 35 |
+
tail['supplied_post_weapon_state']=False;tail['resumed_after_actual_return']=True
|
| 36 |
+
return {'initial':initial,'entry_execution':entry,'before_weapon':before,'weapon':w,'tail':tail,'final':weapon_state(m),'main_stop':54464 if tail else 54453}
|
| 37 |
+
|
| 38 |
+
def main():
|
| 39 |
+
q,raw,h,ins=source();rows=[]
|
| 40 |
+
cases=[('ready',{}),('lowering-wait',{PS+148:2,PS+44:200}),('lowering-complete',{PS+148:2,PS+44:16}),('raising-complete',{PS+148:1,PS+44:16}),('reload-complete',{PS+220:8,PS+44:16}),('held-reload',{PS+220:8,PS+44:16,FRAME+20:32}),('action-reentry',{PS+220:1,FRAME+20:64}),('blocked-action',{PS+220:512|128}),('disabled',{PS+12:256}),('dead',{PS+208:0}),('special-mode',{PS+220:1024}),('frame-gate',{FRAME+232:1}),('id27',{PS+312:27|(1<<8),FRAME+24:27}),('mode-local',{PS+312:1|(1<<8)|(1<<16),FRAME+24:1,4244+432+12:0}),('incremental-reload',{PS+312:1|(1<<8)|(3<<24),PS+220:8,PS+44:16,FRAME+20:32,FRAME+24:1,4028+432:16}),('new-request',{PS+312:1|(2<<8),FRAME+24:22})]
|
| 41 |
+
for name,changes in cases:
|
| 42 |
+
m=weapon_seed(raw,h,desired=22);m.update({PS+312:22|(2<<8)|(3<<24),PS+316:1,PS+320:22|(5<<8)|(3<<24),FRAME+20:0,PS+68:8,FRAME+212:3,35024028:0,35023932:16,FRAME+36:0});m.update(changes);p=main_chain(ins,m);p['name']=name;p['supplied_changes']={str(k):v for k,v in changes.items()};rows.append(p)
|
| 43 |
+
write_json(Path('docs/research/qvm-weapon-return-chains.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Actual main54444..54451 then weapon50747..51801 staged in shared parent locals. Actual exit53046 permits resumed54455..54463;51802 suspends caller. Void epilogue/POP are boundary bridges, not full VM execution. No firing51802..53045, final native snap54471 or earlier main tick; no full tick/reference runtime claim.'})
|
| 44 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_weapon_return_chains.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest,copy
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_main_consumers import reload_state,interaction_state,weapon_state as prefix_state
|
| 4 |
+
from test_qvm_weapon_select import select_state
|
| 5 |
+
from test_qvm_weapon_guards import guard_state
|
| 6 |
+
from test_qvm_weapon_ready import ready_state
|
| 7 |
+
from test_qvm_reload_complete import reload_complete_state
|
| 8 |
+
from test_qvm_weapon_phases import phase_state
|
| 9 |
+
from test_qvm_torso_selector import request
|
| 10 |
+
from test_qvm_locomotion_prefix import animation
|
| 11 |
+
from test_qvm_locomotion import locomotion_state
|
| 12 |
+
from test_qvm_water_events import enqueue,expected
|
| 13 |
+
|
| 14 |
+
def selection_state(test,p):
|
| 15 |
+
a=copy.deepcopy(p['initial']);test.assertEqual(p['prefix']['initial'],{k:a[k] for k in p['prefix']['initial']});a.update(prefix_state(p['prefix']));a['weapons'][a['slot']]=a['packed'];test.assertEqual(a,p['before_selection'])
|
| 16 |
+
if p['selection_execution'] and p['selection_execution']['children']:
|
| 17 |
+
child=p['selection_execution']['children'][0]['effect'];test.assertEqual(child['initial'],a);a=select_state(child)
|
| 18 |
+
test.assertEqual(p['final'],a);return a,p['stop']
|
| 19 |
+
class WeaponReturnChainTests(unittest.TestCase):
|
| 20 |
+
@classmethod
|
| 21 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-weapon-return-chains.json').read_text())
|
| 22 |
+
def test_main_entry_live_children_and_exact_weapon_handoff(self):
|
| 23 |
+
self.assertEqual(len(self.r['probes']),16)
|
| 24 |
+
for p in self.r['probes']:
|
| 25 |
+
a=copy.deepcopy(p['initial']);self.assertEqual([c['instruction'] for c in p['entry_execution']['calls']],[54447,54450])
|
| 26 |
+
for child,oracle in zip(p['entry_execution']['children'],[reload_state,interaction_state]):
|
| 27 |
+
q=child['effect'];self.assertEqual(q['initial'],{k:a[k] for k in q['initial']});a.update(oracle(q));self.assertEqual(q['final'],{k:a[k] for k in q['final']})
|
| 28 |
+
self.assertEqual(a,p['before_weapon']);self.assertEqual(a,p['weapon']['initial'])
|
| 29 |
+
def test_every_weapon_stage_exact_state_and_stop(self):
|
| 30 |
+
oracles={'guards':guard_state,'ready':ready_state,'reload':reload_complete_state,'phases':phase_state};entries={'guards':50923,'ready':51207,'reload':51365,'phases':51633}
|
| 31 |
+
for p in self.r['probes']:
|
| 32 |
+
a=copy.deepcopy(p['weapon']['initial']);stop=None
|
| 33 |
+
for stage in p['weapon']['stages']:
|
| 34 |
+
name,q=stage['name'],stage['probe'];self.assertEqual(q['initial'],a)
|
| 35 |
+
if name=='selection':a,stop=selection_state(self,q)
|
| 36 |
+
else:
|
| 37 |
+
self.assertEqual(stop,entries[name]);result=oracles[name](q);a,stop=result[:2];self.assertEqual(q['execution']['stop'],stop);self.assertEqual(q['final'],a)
|
| 38 |
+
self.assertEqual(p['weapon']['final'],a);self.assertEqual(p['weapon']['stop'],stop)
|
| 39 |
+
def test_actual_returns_resume_exact_main_tail_other_paths_suspend(self):
|
| 40 |
+
for p in self.r['probes']:
|
| 41 |
+
w=p['weapon'];a=copy.deepcopy(w['final']);self.assertEqual(w['returned'],w['stop']==53046);self.assertEqual(p['tail'] is not None,w['returned'])
|
| 42 |
+
if p['tail']:
|
| 43 |
+
tail=p['tail'];self.assertFalse(tail['supplied_post_weapon_state']);self.assertTrue(tail['resumed_after_actual_return']);self.assertEqual([c['instruction'] for c in tail['execution']['calls']],[54456,54459,54462]);self.assertEqual(tail['initial'],{k:a[k] for k in tail['initial']});torso,loco,water=[x['effect'] for x in tail['execution']['children']];r=request(torso)
|
| 44 |
+
if r is not None:animation(a,39482,r,0)
|
| 45 |
+
self.assertEqual(torso['final'],{k:a[k] for k in torso['final']});self.assertEqual(loco['initial'],{k:a[k] for k in loco['initial']});a.update(locomotion_state(loco)[0]);self.assertEqual(water['initial'],{k:a[k] for k in water['initial']});a['queue']=enqueue(a['queue'],expected(water));self.assertEqual(tail['final'],{k:a[k] for k in tail['final']})
|
| 46 |
+
self.assertEqual(p['final'],a);self.assertEqual(p['main_stop'],54464 if w['returned'] else 54453)
|
| 47 |
+
def test_pre_switch_mode_local_is_preserved_after_packed_mode_change(self):
|
| 48 |
+
p=next(p for p in self.r['probes'] if p['name']=='mode-local');stage=next(s['probe'] for s in p['weapon']['stages'] if s['name']=='ready');self.assertEqual(stage['preserved_parent_locals'],{'id':1,'mode':1});self.assertEqual(stage['initial']['packed']>>16&255,0);self.assertEqual(p['weapon']['stop'],51802)
|
| 49 |
+
if __name__=='__main__':unittest.main()
|