AWJ wrote:
Even if I can't run your scripts without IDA, I can port them to my own disassembler

enjoy
https://pastebin.com/sMW8wLXS me commented some portions of code, the rest is my own or system library functions...
all nes koei games has a full list of bitecode procedures and can be disassembled automatically using my scripts and ida

. but the offsets are for my own loader, they has no correlation with real offsets except lower bits...
some opcodes I didn't reversed deeply and just nailed briefly, I took from your description (comments are given). bitfield opcodes never used in the nes bytecode (as I see), as well as the relative branches... so I just didn't care about it by now..
AWJ wrote:
Well, I've found one use for the "hole" at frameptr+8. Your tip that there was also compiler-generated native code was just what I needed. Take a look at the routine at 1F/E24B in Ishin no Arashi, 1F/E37A in Rot3K2 or 1F/E2E3 in L'Empereur (the same routine exists in BKoAC and probably most/all of the games, but it's not always in the fixed bank. I guess the games that have it in the fixed bank are the ones with the most compiler-generated native code)
The purpose of this routine seems to be to create a bytecode-compatible stack frame for a native-code function, and to clean up that stack frame when that function exits (it does some 6502 stack manipulation to wedge its cleanup code after the RTS of the "wrapped" function). Anyway, this wrapper routine uses the byte at frameptr+8 to store the number of bytes it has copied from $0080 to the bytecode stack, in order to restore that number of bytes back to $0080 when the wrapped native-code function exits.
It looks like compiler-generated native code uses $0080~ as local variable storage, and each native-code function uses this wrapper to preserve its caller's local variables (if any) and to allocate stack space for the arguments it needs to pass to any functions that it calls.
this is actually a native version of the bytecode exec procedure. it is used for every native procedure start. the same way as for bytecode procedures. but instead this functions executes the real 6502 asm and then returns back to the caller routine. it does the same thing as for bytecode procedures, prepares the stack and executes the native code instead of the bytecode. it gets the same 16-bit signed value to assign the local variables buffer for procedure, but has an extra parameter byte, which is used to backup a number of vm stack bytes to 80-buffer. it will be stored in your 8-byte stack offset. but, I haven't seen any functions used any value apart from 0 here. l'empereur and uncharted waters never used this byte for sure. it's always 0. so copy to 80 buffer never used there. I doubt it used anywhere else... so this is for sure redundant leftover of some planned but never used feature of the compiler to save some stack parameters..