Author Topic: REQ* Opcodes?  (Read 11346 times)

halkun

  • Global moderator
  • *
  • Posts: 2097
  • NicoNico :)
    • View Profile
    • Q-Gears Homepage
REQ* Opcodes?
« on: 2006-06-27 01:11:23 »
What on earth are these things? They seem to be REturn Question. It's a method to have two script threads to "talk" to each other.

However, I'm stumped on what's calling who. Can someone step through the arguments?

Thanks.

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Re: REQ* Opcodes?
« Reply #1 on: 2006-06-27 10:57:49 »
Why not just "force" Qhimm to find the documentation he made while making his script editor? :P IMHO, it's not a good idea to "guess" the meaning of the opcodes.

if(reader == Qhimm)
    print
anonymous
else if(reader == EmperorSteele)
   print
dzuigo
else
   print
dziugo

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
Re: REQ* Opcodes?
« Reply #2 on: 2006-06-27 11:47:43 »
I documented the REQ* opcodes on the wiki, though it might not make a terrible amount of sense if you don't already understand how FF7's scripts are run. :P

Essentially in a given field file you have a number of entities. Some of these entities are connected with a physical object on the screen, while others are simply abstract (I believe earlier documentation referred to these as "entities" and "characters"; the number of each are defined in the field file header). Each entity has up to 32 "member functions", or scripts (the offsets of these are stored in the large arrays of shorts early in the field file). Only the entity itself is allowed to execute these scripts, so no entity can directly "call" someone else's scripts.

Now, all entities run their scripts in parallel. In separate "threads", if you will. Unless specified, each entity will just execute their "init" function (script 0), at base priority. "Triggers" can be set up in the field to activate other member scripts, i.e. "ontouch", "onactivate" etc. Also, one entity can request that another entity runs one of its member scripts. This is done with the REQ* commands. A target of a REQ* command will pause his current execution and instead begin executing the requested script at a specified priority. If the target entity is already executing something else at a higher priority, the requested script will be queued at its specified priority slot. If the target entity is already executing or waiting to execute something at the specified priority, the requesting entity will either block (wait) or silently fail the request.

The different variations of the REQ* commands specify how the requesting entity should behave while the target entity is running the code. The REQ command simply requests that the target entity starts running the script, but does not care if the request is successfully completed or not, or when the script is actually started. The requesting entity will immediately continue its own execution, regardless of what the target entity is executing. The REQSW (request-start-wait) command behaves similarly, but will block (wait) until the target entity actually begins to execute the script, then continue executing in parallel. This version will not fail silently like REQ, since it always succeeds (sooner or later). The REQEW (request-end-wait) command does all this but blocks until (surprise) the target entity has finished executing the script (indicated by the RET command, which btw tells the target entity to resume execution at whatever lower priority it was executing on before, or simply halt at base priority). Finally, the PRQ* commands simply means that instead of referring to a specific entity, you refer to the entity associated with a character in the current party (0, 1 or 2).

This kind of multithreading makes it relatively easy to make characters perform things on-screen, regardless if they're controlled from a central "story script" entity or triggered by some event in a character or object entity. To get the characters to do something simultaneously, all you would have to do is issue the REQSW command to the relevant script in their entities. To make Cloud walk across the screen and only once he's arrived have the door open, you first request Cloud's entity's "walk over there" script with REQEW, followed the door's "open" script.

Piece of cake? :P

Akari

  • *
  • Posts: 766
    • View Profile
Re: REQ* Opcodes?
« Reply #3 on: 2006-07-05 19:11:56 »
Now, all entities run their scripts in parallel. In separate "threads", if you will. Unless specified, each entity will just execute their "init" function (script 0), at base priority. "Triggers" can be set up in the field to activate other member scripts, i.e. "ontouch", "onactivate" etc. Also, one entity can request that another entity runs one of its member scripts. This is done with the REQ* commands. A target of a REQ* command will pause his current execution and instead begin executing the requested script at a specified priority. If the target entity is already executing something else at a higher priority, the requested script will be queued at its specified priority slot. If the target entity is already executing or waiting to execute something at the specified priority, the requesting entity will either block (wait) or silently fail the request.

How are the scripts executed? Did they run only once, or they called on every game logic update?

What script do when it executed animation or start movie? Does it wait untill animation ands and continue execution or it just start animation and continue execution before animation ends?

Could you tell a bit more about priority? What are "base priority"? What will script do if it executed something at priority 4, wait something at priority 4  and we want it to execute something at priority 4? How are th priority queue organized?

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
Re: REQ* Opcodes?
« Reply #4 on: 2006-07-06 10:59:21 »
How are the scripts executed? Did they run only once, or they called on every game logic update?
The first script in each entity (script 0, the init script) are called once, when the field file is loaded. They are fully executed up until the mandatory RET command (first entity's script is run, then second entity's, and so forth). Typically the init scripts do not contain any REQ* commands.

After the "initialization", scripts are run in parallel, a few instructions on every game frame (30fps). Entity 0 runs a few instructions, then entity 1, and so forth.

Quote from: Akari
What script do when it executed animation or start movie? Does it wait untill animation ands and continue execution or it just start animation and continue execution before animation ends?
This is not fully known (at least by me); it could depend on the specific opcode used to start the animation. A lot of opcodes are available in both synchronous (wait until complete) and asynchronous (don't wait) variants.

Quote from: Akari
Could you tell a bit more about priority? What are "base priority"? What will script do if it executed something at priority 4, wait something at priority 4  and we want it to execute something at priority 4? How are th priority queue organized?
Base priority is what scripts are executing at "normally". The init scripts are run at base priority, and probably trigger scripts as well. When REQuested at a higher priority, the base priority is preempted, its state saved, and the entity runs the requested script at the requested priority. When this is done, it resumes where it left off at the lower priority. There is not really any "queue" for priorities; if the requested priority is busy, the calling entity will either block and try again at the next opportunity (next frame), or give up and continue its own execution. There is as such no real scheduling, and starvation is possible in severe cases.

Akari

  • *
  • Posts: 766
    • View Profile
Re: REQ* Opcodes?
« Reply #5 on: 2006-07-06 16:14:39 »
I have few more question.

First is about memory bank. (I think it's for Halkun... or not?)
The savemam save all memory bank data from 1/2 3/4 7/F B/C D/E (according to Gears) but the size of those are 256 each. So there are five blocks * 256, but acording to PDF you showed earlier second memory bank contains 256 * 2 bytes. Or I misunderstood you?

After the "initialization", scripts are run in parallel, a few instructions on every game frame (30fps). Entity 0 runs a few instructions, then entity 1, and so forth.

After initialization (script 0) entity start to run some other script, or it wait until some trigger will be activated?

How many instruction are executed on every game frame? Why not run whole script at once (maybe until synchronous instruction?).

Quote
Base priority is what scripts are executing at "normally". The init scripts are run at base priority, and probably trigger scripts as well. When REQuested at a higher priority, the base priority is preempted, its state saved, and the entity runs the requested script at the requested priority.

So base priority is zero (the priority takes 3 bit so it can be from 0 till 7)?

Quote
When this is done, it resumes where it left off at the lower priority. There is not really any "queue" for priorities; if the requested priority is busy, the calling entity will either block and try again at the next opportunity (next frame), or give up and continue its own execution. There is as such no real scheduling, and starvation is possible in severe cases.

So there can be 8 depth calls. If we run script at zero priority, then requesr to run at firts, then at second ... until seventh priority. All previous call will wait until others finished.

And there are 8 priority slots there are may be such situation:
1) we run script at 0 priority.
2) we request script at priority 1 (the 0 pr stops and 1pr starts)
3) we request script at 7 pr.  (the 1 pr stops and 7pr starts)
4) we request one more script at 7 pr (it placed in priority slot 7)
5) we request script at 3 pr (it placed in priority slot 3)
6) script 7 finished (start script 7 in priority slot)
7) script 7 finished (start script 3 in priority slot)
8) script 3 finished (continued script 1)
9) script 1 finished (continued script 0)
A) script 0 finished

Is this true?

halkun

  • Global moderator
  • *
  • Posts: 2097
  • NicoNico :)
    • View Profile
    • Q-Gears Homepage
Re: REQ* Opcodes?
« Reply #6 on: 2006-07-06 17:15:31 »
I have few more question.

First is about memory bank. (I think it's for Halkun... or not?)
The savemam save all memory bank data from 1/2 3/4 7/F B/C D/E (according to Gears) but the size of those are 256 each. So there are five blocks * 256, but acording to PDF you showed earlier second memory bank contains 256 * 2 bytes. Or I misunderstood you?

I can answer this one.

The 16 bit banks are still refrenced by an 8 bit pointer. Even though the 16 bit opcodes have a 16 bit-wide operand at the end, if the bank refrenced is a 16-bit bank, only the least significant byte is used as an address.

16-bit banks are still only 256 bytes long.

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
Re: REQ* Opcodes?
« Reply #7 on: 2006-07-07 08:38:35 »
I have few more question.

First is about memory bank. (I think it's for Halkun... or not?)
The savemam save all memory bank data from 1/2 3/4 7/F B/C D/E (according to Gears) but the size of those are 256 each. So there are five blocks * 256, but acording to PDF you showed earlier second memory bank contains 256 * 2 bytes. Or I misunderstood you?
Probably a misunderstanding; all script memory banks contain 256 bytes, where any two adjacent bytes can also be treated as a single 16-bit value. Judging by the scripts though, the variables in these banks are probably pre-allocated without overlaps, so if you see a 16-bit reference to an address in the script, you can be reasonably sure that address will always be referenced as a 16-bit variable.

Quote from: Akari
After initialization (script 0) entity start to run some other script, or it wait until some trigger will be activated?

How many instruction are executed on every game frame? Why not run whole script at once (maybe until synchronous instruction?).
If I recall correctly, the init scripts (script 0) are a bit special in that they are first fully executed (up to the RET instruction), but they can then also contain more code after that RET instruction. This code (let's call it the default script, or script 0a :) ) is what will continue to execute (with normal, parallell execution) after the init scripts are complete. That is why many instances of script 0 end in two RET instructions, which signify an empty default script. The second RET marks the end of the default script, at which the entity will simply begin to do nothing at base priority (the priority is still busy, it just doesn't do anything useful).

I think there are eight or so instructions executed at each frame, unless one of them is synchronous in some way, in which case it will automatically be the last one to be executed during that frame. The scripts are executed in this way to mimic the parallelism concept as closely as possible; thus you can write two scripts regardless of each other, and their events will happen roughly in parallel without the need to explicitly synchronize and wait for frames in the scripts. If the scripts executed all the way up until a synchronous instruction, this would result in a drastically different "clock speed" for each entity, depending on their use of syncronous events. I agree that it would indeed make more sense not having to worry about an "instruction limit" for each frame, but it also means you don't have to worry about manually timing every aspect of your script. That having been said, a lot of scripts depend almost entirely on WAIT and other synchronous instructions anyway.

I guess once you have your script engine running, you can experiment and see if there are some deeper reason for the "x instructions per frame". I'm betting it was just a design choice, that scripts should be running at a virtual "clock speed" in order to enforce the idea of parallelism.

Quote from: Akari
So base priority is zero (the priority takes 3 bit so it can be from 0 till 7)?
Actually they're counted the other way, so base priority is 7.

Quote from: Akari
So there can be 8 depth calls. If we run script at zero priority, then requesr to run at firts, then at second ... until seventh priority. All previous call will wait until others finished.

And there are 8 priority slots there are may be such situation:
1) we run script at 0 priority.
2) we request script at priority 1 (the 0 pr stops and 1pr starts)
3) we request script at 7 pr.  (the 1 pr stops and 7pr starts)
4) we request one more script at 7 pr (it placed in priority slot 7)
5) we request script at 3 pr (it placed in priority slot 3)
6) script 7 finished (start script 7 in priority slot)
7) script 7 finished (start script 3 in priority slot)
8) script 3 finished (continued script 1)
9) script 1 finished (continued script 0)
A) script 0 finished

Is this true?
Not quite... The "priority slot" is the information required to resume execution at a lower priority after the current request is completed. They are not really "queues", and more importantly, the priority slots at and above the currently executing priority are always empty. As such, when you (as in point 4 above) request something at top priority while something is already executing there, the request will simply fail; depending on the opcode used (REQ/REQSW/REQEW), the calling entity will then either forget the request and continue execution, or abort and try again the next game frame (next round of script execution). It is thus up to the calling entity to continuously retry the request, meaning that the lower-priority request might begin to execute before you get a chance to request the second top-priority script.

Other than that, and the priority numbering, you seem to have understood the base mechanics fairly well.
« Last Edit: 2006-07-07 14:17:40 by Qhimm »

Akari

  • *
  • Posts: 766
    • View Profile
Re: REQ* Opcodes?
« Reply #8 on: 2006-07-09 02:55:16 »
I can answer this one.

The 16 bit banks are still refrenced by an 8 bit pointer. Even though the 16 bit opcodes have a 16 bit-wide operand at the end, if the bank refrenced is a 16-bit bank, only the least significant byte is used as an address.

16-bit banks are still only 256 bytes long.

Ok.. I think I get it  :-)

One more question... could you explain what BANK 0 do. I getting confused with
Code: [Select]
Finally,bank 0 is used if you want to inject an immediate value in a command where a bank address is
supposed to go.
description =(

Cyberman

  • *
  • Posts: 1572
    • View Profile
Re: REQ* Opcodes?
« Reply #9 on: 2006-07-09 05:21:01 »
One more question... could you explain what BANK 0 do. I getting confused with
Code: [Select]
Finally,bank 0 is used if you want to inject an immediate value in a command where a bank address is
supposed to go.
description =(
when using a bank identified as 0 the value following is an immediate value instead of a pointer to one of 256 variables.

Cyb

halkun

  • Global moderator
  • *
  • Posts: 2097
  • NicoNico :)
    • View Profile
    • Q-Gears Homepage
Re: REQ* Opcodes?
« Reply #10 on: 2006-07-09 22:03:25 »
Yup, then the bank refrenced is 0 then the offest address that's usually refrenced at the end the opcode argumnets turns into the immidaite value. to be used instead.


Now for *MY* question.

Looking at my script dumper, I'm not getting how to parse the REQ* arguments...

for example, from startmap. Yufi, script 1
Quote
23f:    req(11,74)

In your doc, you said that it's REQ(E,P/F)

According to this, the entity is #11, but there are only 4 entites in this script.

Also, is it Priority 7, script 4?

I need the numbers unjumbled....

Cyberman

  • *
  • Posts: 1572
    • View Profile
Re: REQ* Opcodes?
« Reply #11 on: 2006-07-09 23:56:45 »
First what field location is this? One of the Wuti ones?

Second acording to QhimmDocs <TM>
It's priority 7 script 4 on entity 11.

You probably should dump it like
REQ(ENTITY_11, SCRIPT_4, PRIORITY_7);

I don't really know about the entity ID though.
Cloud is in almost ALL of them except the corel materia related ones.
If there are 4 entities that means it's probably and it's the WUTI scene it's cloud yufi Tifa Arial I think.  Although I do remember Barret coming in after yufi steals the materia.  Hmmm.

It's been a while since I've looked at the field locations and with my windows based PC dying all the time it won't be easy either.

The scripts define everything that should be in interactable in the script by the entity list right?
Perhaps as part of your script dump system you should dump the entity list and use the name instead of the ID's given for each entity.
IE
cloud
tifa
POTION
SAVE

REQ(cloud_0, PRIORITY_7, SCRIPT_4); or what have you.

Is there an event script for when the action button is pressed on something?

How are doors etc opened for example.  That's what I'm thinking about.
I know yufi's basement thing is a field script event.
I'm curious about the interaction a bit.

Cyb

halkun

  • Global moderator
  • *
  • Posts: 2097
  • NicoNico :)
    • View Profile
    • Q-Gears Homepage
Re: REQ* Opcodes?
« Reply #12 on: 2006-07-10 00:37:20 »
It's from STARTMAP.

That still doen't make sense that coud is entity 11 when there are 4 and cloud is entity 1

Akari

  • *
  • Posts: 766
    • View Profile
Re: REQ* Opcodes?
« Reply #13 on: 2006-07-10 02:29:24 »
The yufi script 1 look like this. There is no REQ in there

Code: [Select]
script1()
{
#C  WINDOW(01 00 00 00 00 8A 00 A9 00)
    ASK(05 01 00 00 09 00)
    JMPF(15) // go check results (#0)

#1  WINDOW(01 00 00 00 00 81 00 59 00)
    ASK(05 01 01 00 04 00)
    JMPFL(9D 00) // (#B)

#0  IFUBL(50 00 00 00 07 00) // if not - go check other value (#2)
    JMPB(1B) // create next window (#1)
    JMPFL(90 00) // (#A)

#2  IFUBL(50 00 01 00 0A 00) // if not - go check other value (#3)
    SET-BYTE!(20 1E 00)
    RET // probably wrong... it should not be here
    JMPFL(81 00) // (#A)

#3  IFUBL(50 00 02 00 08 00) // if not - go check other value (#4)
    SPECIAL(FB 01) // Lock Battles
    JMPFL(74 00) // (#A)

#4  IFUBL(50 00 03 00 08 00) // if not - go check other value (#5)
    SPECIAL(FB 00) // UnLock Battles
    JMPFL(67 00) // (#A)

#5  IFUBL(50 00 04 00 08 00) // if not - go check other value (#6)
    SPECIAL(FC 01) // Lock Movies
    JMPFL(5A 00) // (#A)

#6  IFUBL(50 00 05 00 08 00) // if not - go check other value (#7)
    SPECIAL(FC 00) // UnLock Movies
    JMPFL(4D 00) // (#A)

#7  IFUBL(50 00 06 00 07 00) // if not - go check other value (#8)
    SPECIAL(FE) // Global Reset
    JMPFL(41 00) // (#A)

#8  IFUBL(50 00 07 00 29 00) // if not - go check other value (#9)
    SPECIAL(FD 00 02) // give default name
    SPECIAL(FD 01 03) // give default name
    SPECIAL(FD 02 04) // give default name
    SPECIAL(FD 03 05) // give default name
    SPECIAL(FD 05 06) // give default name
    SPECIAL(FD 06 07) // give default name
    SPECIAL(FD 08 08) // give default name
    SPECIAL(FD 04 0A) // give default name
    SPECIAL(FD 07 09) // give default name
    JMPFL(13 00) // (#A)

#9  IFUBL(50 00 08 00 0C 00) // if not - go check other value (#A)
    MAPJUMP(74 00 00 00 00 00 00 00 00)
#A  RET

#B  IFUBL(50 00 00 00 08 00) // if not - go check other value (#D)
    JMPBL(C9 00) // (#C)
    JMPFL(02 01)

#D  IFUBL(50 00 01 00 DF 00) // if not - go check other value (#E)
    AKAO(00 00 00 C0 7F 00 00 00 00 00 00 00 00)
    AKAO(00 00 00 A0 7F 00 00 00 00 00 00 00 00)
    AKAO(00 00 00 A1 7F 00 00 00 00 00 00 00 00)
    AKAO(00 00 00 A2 7F 00 00 00 00 00 00 00 00)
    AKAO(00 00 00 A3 7F 00 00 00 00 00 00 00 00)
    AKAO2(00 00 00 C8 FF 7F 00 00 00 00 00 00 00 00)
    AKAO2(00 00 00 E4 00 00 00 00 00 00 00 00 00 00)
    AKAO2(00 00 00 B0 00 00 00 00 00 00 00 00 00 00)
    AKAO2(00 00 00 B1 00 00 00 00 00 00 00 00 00 00)
    AKAO2(00 00 00 B2 00 00 00 00 00 00 00 00 00 00)
    AKAO2(00 00 00 B3 00 00 00 00 00 00 00 00 00 00)
    SPECIAL(00 F2 00 00 00 28 3F 00 00 00 00 00 00 00
            00 F2 00 00 00 29 3F 00 00 00 00 00 00 00
            00 F2 00 00 00 2A 3F 00 00 00 00 00 00 00
            00 F2 00 00 00 2B 3F 00 00 00 00 00 00 00 00
    JMPFL(1E 00) // (#10)

#E  IFUBL(50 00 02 00 0B 00) // if not - go check other value (#F)
    SPECIAL(F9)
    SPECIAL(F9)
    SPESIAL(F9)
    JMPFL(0E 00) // (#10)

#F  IFUBL(50 00 03 00 07 00)
    BATTLE(00 E7 03)
    MHMMX()
#10 RET
}
« Last Edit: 2006-07-10 02:45:12 by Akari »

EmperorSteele

  • *
  • Posts: 933
    • View Profile
Re: REQ* Opcodes?
« Reply #14 on: 2006-07-10 06:28:01 »
Why not just "force" Qhimm to find the documentation he made while making his script editor? :P IMHO, it's not a good idea to "guess" the meaning of the opcodes.

if(reader == Qhimm)
    print
anonymous
else if(reader == EmperorSteele)
   print
dzuigo
else
   print
dziugo

...You're making fun of me for always misspelling your name, aren't you? =(

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Re: REQ* Opcodes?
« Reply #15 on: 2006-07-10 06:59:06 »
Who? Me? :P I just couldn't think of any other variation of my name, and a reason to use it. Sorry for that.

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
Re: REQ* Opcodes?
« Reply #16 on: 2006-07-10 08:51:17 »
Looking at my script dumper, I'm not getting how to parse the REQ* arguments...

for example, from startmap. Yufi, script 1
Quote
23f:    req(11,74)

In your doc, you said that it's REQ(E,P/F)

According to this, the entity is #11, but there are only 4 entites in this script.

Also, is it Priority 7, script 4?

I need the numbers unjumbled....
First of all, Akari is right. There is no such REQ in STARTMAP. Most likely you are misinterpreting the SPECIAL opcode; it too has variable length, depending on the second byte (the sub-opcode). The only valid sub-opcodes for SPECIAL are 0xF5 through 0xFF, and their corresponding lengths are 2, 6, 4, 4, 2, 2, 3, 3, 4, 2 and 2 bytes, respectively (where 2 bytes means no additional arguments, just the opcode and sub-opcode). In this case, the SPECIAL opcode uses one byte more than you decoded, meaning the next command is actually a jump, not a request.

As for the decoding of REQ arguments, you have no doubt deduced from my documentation that the priority is stored in 3 bits and the script ID in 5 bits. The upper three bits of the second argument is the priority, and the lower five bits is the script ID.

Code: [Select]
#2  IFUBL(50 00 01 00 0A 00) // if not - go check other value (#3)
    SET-BYTE!(20 1E 00)
    RET // probably wrong... it should not be here
    JMPFL(81 00) // (#A)
This is also incorrectly decoded, opcode 0x81 is actually SET-WORD!, meaning it uses one more byte, thus there is no RET immediately following it. Where is this script dump from though? It is quite detailed (apart from not decoding arguments properly), and obviously has some manual additional decoding work done to it. Is this how lasyan's script dumper's output looks like? (I have never tried it out)

Synergy Blades

  • Guest
Re: REQ* Opcodes?
« Reply #17 on: 2006-07-10 12:42:39 »
Hmm. Are there any more variable-length (or otherwise out-of-the-ordinary) opcodes aside from kawai and special?

Akari

  • *
  • Posts: 766
    • View Profile
Re: REQ* Opcodes?
« Reply #18 on: 2006-07-10 14:46:33 »
Where is this script dump from though? It is quite detailed (apart from not decoding arguments properly), and obviously has some manual additional decoding work done to it. Is this how lasyan's script dumper's output looks like? (I have never tried it out)

I created it manually yestarday  8-)

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Re: REQ* Opcodes?
« Reply #19 on: 2006-07-10 18:42:34 »
The only valid sub-opcodes for SPECIAL are 0xF5 through 0xFF, and their corresponding lengths are 2, 6, 4, 4, 2, 2, 3, 3, 4, 2 and 2 bytes, respectively (where 2 bytes means no additional arguments, just the opcode and sub-opcode).
It's 3 bytes for 0xF5.

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
Re: REQ* Opcodes?
« Reply #20 on: 2006-07-10 18:52:49 »
It's 3 bytes for 0xF5.
Right you are, my mistake.