Shop OBEX P1 Docs P2 Docs Learn Events
Fast Bytecode Interpreter - Page 13 — Parallax Forums

Fast Bytecode Interpreter

1101113151630

Comments

  • cgracey wrote: »
    Cluso99 wrote: »
    Obviously skip works out a count to know how many instructions to skip over. Could that value be used to decrement the REP block size?
    If yes, easy/complex to do? If its complex, then its a caveat for skip instructions.

    It's way too complicated. It's like mixing polar and Cartesian domains. I imagine brushing my teeth while riding a dirt bike.

    An alternative I envisioned was for skip to send rep a signal when it skips. Just hold the count, or correct it.

    If skip can do this, it's usable inside a rep, outside one and in both cog and hub execute modes. And it's easy to understand.

    Basically, Rep repeates X number of executed instructions, and a HUBEXEC forced nop would count as a skipped instruction.

    @cgracey

    Possible? Second question, do we care or need the same code to work cog and hub mode? In HUB, it would be slow, but would do the same thing.

    I'm fine with skip as it exists now, BTW.

  • CSKIP
  • jmgjmg Posts: 15,140
    potatohead wrote: »
    Second question, do we care or need the same code to work cog and hub mode? In HUB, it would be slow, but would do the same thing.
    Up until this opcode, I believe all P2 code was location agnostic in fundamental operation.

    That meant users could cut and paste working examples, and not worry too much about the inner details.
    Anything that can cause crash-and-burn, needs very careful management.

    One solution would be explicit COG_SKIP and HUB_SKIP forms, that could be build-time checked for the correct final locations.
    Tool conditionals that could check assigned segment, could even adjust the forms so they did work as expected.

    Of course, that is making the tools do more housekeeping, which is what PCs do best :)

  • @jmg :D
  • Cluso99Cluso99 Posts: 18,066
    While it's really nice to have code that just runs in cog/lut and hub.

    However, I tend to think that there are probably undiscovered cases where that is just not practical.

    I am more likely, I think, to specify precisely where my code will run, cog/lut or hub. I guess I really like to control my code from a nuts and bolts point of view. Others I am sure will disagree and want their code to run everywhere.
  • potatoheadpotatohead Posts: 10,253
    edited 2017-03-24 03:43
    I'm agnostic on it. Most will work, and that's good. Where timing is significant, it's gonna need to live where it's written.

    My intent here is more about rep and skip playing together in a consistent way. If skip can trigger the rep circuit to hold its count, the two work together consistently, and in an easy to document way.

    But, that may prove too much and may kill fmax.

    If so, fine. It's a very useful cog tool. It probably isn't needed in HUB at all.

  • cgraceycgracey Posts: 14,133
    I just realized there's a simple way to handle this:

    Only skip ahead by multiple instructions if REP is not active.

    So, disallow skipping multiple instructions if (hub exec | branch | REP active). Adding the REP-active element should do it.

    This means that inside a REP block, SKIP will just cancel instructions, not skip over more than one at a time.
  • That works too. :D
  • Chip, I was about to suggest that. Glad you figured it out.
  • Yeah, cleans it right up. That's just as easy to document and understand.

  • jmgjmg Posts: 15,140
    cgracey wrote: »
    I just realized there's a simple way to handle this:

    Only skip ahead by multiple instructions if REP is not active.

    So, disallow skipping multiple instructions if (hub exec | branch | REP active). Adding the REP-active element should do it.

    This means that inside a REP block, SKIP will just cancel instructions, not skip over more than one at a time.

    That sounds safest, and avoids the nasty surprises aspect.
    It restores the ability to move tested code about, without 'bonus-fish-hooks', which was always a significant and hard-won feature in P2.
  • kwinnkwinn Posts: 8,697
    cgracey wrote: »
    Roy Eltham wrote: »
    Chip,
    Why are we "hidebound to keeping it under 7 characters" ???? I think only you are thinking that is a requirement, and it's just NOT.

    I know. I'm just used to an 8-spaces-per-tab world.

    Upon someone pointing out that we could use longer names, I reviewed all of our mnemonics and I think they are sufficiently expressive at under eight characters, each.

    The only problem is this new instruction that CALLs and SKIPs, but with a single operand.

    So why not just HOP and HOPRET. Under 8 characters and like skip hop implies going from one location to another while bypassing some intermediate ones.
  • cgraceycgracey Posts: 14,133
    kwinn wrote: »
    cgracey wrote: »
    Roy Eltham wrote: »
    Chip,
    Why are we "hidebound to keeping it under 7 characters" ???? I think only you are thinking that is a requirement, and it's just NOT.

    I know. I'm just used to an 8-spaces-per-tab world.

    Upon someone pointing out that we could use longer names, I reviewed all of our mnemonics and I think they are sufficiently expressive at under eight characters, each.

    The only problem is this new instruction that CALLs and SKIPs, but with a single operand.

    So why not just HOP and HOPRET. Under 8 characters and like skip hop implies going from one location to another while bypassing some intermediate ones.

    That seems like the best idea, so far.

    SKIP
    HOP
    HOPRET
  • Cluso99Cluso99 Posts: 18,066
    cgracey wrote: »
    kwinn wrote: »
    cgracey wrote: »
    Roy Eltham wrote: »
    Chip,
    Why are we "hidebound to keeping it under 7 characters" ???? I think only you are thinking that is a requirement, and it's just NOT.

    I know. I'm just used to an 8-spaces-per-tab world.

    Upon someone pointing out that we could use longer names, I reviewed all of our mnemonics and I think they are sufficiently expressive at under eight characters, each.

    The only problem is this new instruction that CALLs and SKIPs, but with a single operand.

    So why not just HOP and HOPRET. Under 8 characters and like skip hop implies going from one location to another while bypassing some intermediate ones.

    That seems like the best idea, so far.

    SKIP
    HOP
    HOPRET

    I still prefer

    SKIP
    JMPSKIP
    CALLSKP
  • Cluso99Cluso99 Posts: 18,066
    cgracey wrote: »
    I just realized there's a simple way to handle this:

    Only skip ahead by multiple instructions if REP is not active.

    So, disallow skipping multiple instructions if (hub exec | branch | REP active). Adding the REP-active element should do it.

    This means that inside a REP block, SKIP will just cancel instructions, not skip over more than one at a time.

    Excellent!

    But what do you mean by disallow if "branch"? Seems I missed something :(
  • cgraceycgracey Posts: 14,133
    edited 2017-03-24 06:43
    Cluso99 wrote: »
    cgracey wrote: »
    I just realized there's a simple way to handle this:

    Only skip ahead by multiple instructions if REP is not active.

    So, disallow skipping multiple instructions if (hub exec | branch | REP active). Adding the REP-active element should do it.

    This means that inside a REP block, SKIP will just cancel instructions, not skip over more than one at a time.

    Excellent!

    But what do you mean by disallow if "branch"? Seems I missed something :(

    Because branches cancel an instruction in the pipeline, they actually amount to two instructions: the branch and the trailing instruction after it. That trailing instruction goes by cancelled, but it still cycles the execution signal, which is used to count instructions. So, a branch looks like two instructions. By not counting the trailing instruction, our accounting is good. And in this case of SKIP, we don't want to be looking ahead at future skip bits when a branch is underway, because we are not at the new address, yet, where the PC could be advanced by more than one count per instruction.
  • Cluso99Cluso99 Posts: 18,066
    cgracey wrote: »
    Cluso99 wrote: »
    cgracey wrote: »
    I just realized there's a simple way to handle this:

    Only skip ahead by multiple instructions if REP is not active.

    So, disallow skipping multiple instructions if (hub exec | branch | REP active). Adding the REP-active element should do it.

    This means that inside a REP block, SKIP will just cancel instructions, not skip over more than one at a time.

    Excellent!

    But what do you mean by disallow if "branch"? Seems I missed something :(

    Because branches cancel an instruction in the pipeline, they actually amount to two instructions: the branch and the trailing instruction after it. That trailing instruction goes by cancelled, but it still cycles the execution signal, which is used to count instructions. So, a branch looks like two instructions. By not counting the trailing instruction, our accounting is good. And in this case of SKIP, we don't want to be looking ahead at future skip bits when a branch is underway, because we are not at the new address, yet, where the PC could be advanced by more than one count per instruction.

    Thanks for the explanation. I understand now.
  • cgraceycgracey Posts: 14,133
    I was testing SKIP between cog and hub modes around REP and I realized that we need different types of SKIPs. We need one that cancels single instructions, for use anywhere, and we need another that does the fast skipping in cog memory. The fast skipping doesn't work as simply around branches as the single-SKIP does.

    Here are the instructions now:
    EEEE 1101011 CZ0 DDDDDDDDD 000101100        JMP     D           {WC,WZ}
    EEEE 1101011 CZ0 DDDDDDDDD 000101101        CALL    D           {WC,WZ}
    EEEE 1101011 CZ1 000000000 000101101   *    RET                 {WC,WZ}
    EEEE 1101011 CZ0 DDDDDDDDD 000101110        CALLA   D           {WC,WZ}
    EEEE 1101011 CZ1 000000000 000101110   *    RETA                {WC,WZ}
    EEEE 1101011 CZ0 DDDDDDDDD 000101111        CALLB   D           {WC,WZ}
    EEEE 1101011 CZ1 000000000 000101111   *    RETB                {WC,WZ}
    
    EEEE 1101011 00L DDDDDDDDD 000110000        JMPREL  D/#
    EEEE 1101011 00L DDDDDDDDD 000110001   **   SKIP    D/#
    EEEE 1101011 00L DDDDDDDDD 000110010   **   SKIPF   D/#
    EEEE 1101011 00L DDDDDDDDD 000110011   **   EXECF   D/#
    

    SKIP works everywhere and is completely sane. It can work inside of REP, too. It just cancels instructions as they come up, per the SKIP pattern.

    SKIPF is the fast version for use inside cog memory. Any branch instructions allowed for will need to have another "0" bit to backstop the "1"-series reduction. In other words, if you have a "0" where a branch is, you'll need another "0" after that, and conform to the allowance.

    EXECF is the instruction that jumps to D[9:0] and sets a SKIPF pattern of D[31:10].

    Both SKIP and SKIPF can have _RET_ in front of them for something like "PUSH addr + _RET_ SKIP pattern".

    I've got these implemented, but they need more testing when my brain is fresher.
  • SeairthSeairth Posts: 2,474
    edited 2017-03-24 14:32
    cgracey wrote: »
    I was testing SKIP between cog and hub modes around REP and I realized that we need different types of SKIPs. We need one that cancels single instructions, for use anywhere, and we need another that does the fast skipping in cog memory. The fast skipping doesn't work as simply around branches as the single-SKIP does.

    Here are the instructions now:
    EEEE 1101011 CZ0 DDDDDDDDD 000101100        JMP     D           {WC,WZ}
    EEEE 1101011 CZ0 DDDDDDDDD 000101101        CALL    D           {WC,WZ}
    EEEE 1101011 CZ1 000000000 000101101   *    RET                 {WC,WZ}
    EEEE 1101011 CZ0 DDDDDDDDD 000101110        CALLA   D           {WC,WZ}
    EEEE 1101011 CZ1 000000000 000101110   *    RETA                {WC,WZ}
    EEEE 1101011 CZ0 DDDDDDDDD 000101111        CALLB   D           {WC,WZ}
    EEEE 1101011 CZ1 000000000 000101111   *    RETB                {WC,WZ}
    
    EEEE 1101011 00L DDDDDDDDD 000110000        JMPREL  D/#
    EEEE 1101011 00L DDDDDDDDD 000110001   **   SKIP    D/#
    EEEE 1101011 00L DDDDDDDDD 000110010   **   SKIPF   D/#
    EEEE 1101011 00L DDDDDDDDD 000110011   **   EXECF   D/#
    

    SKIP works everywhere and is completely sane. It can work inside of REP, too. It just cancels instructions as they come up, per the SKIP pattern.

    SKIPF is the fast version for use inside cog memory. Any branch instructions allowed for will need to have another "0" bit to backstop the "1"-series reduction. In other words, if you have a "0" where a branch is, you'll need another "0" after that, and conform to the allowance.

    EXECF is the instruction that jumps to D[9:0] and sets a SKIPF pattern of D[31:10].

    Both SKIP and SKIPF can have _RET_ in front of them for something like "PUSH addr + _RET_ SKIP pattern".

    I've got these implemented, but they need more testing when my brain is fresher.

    So EXECF is a JMP, not a CALL?

    Also, why not make things even more sane and simply cancel skips if you hit a branch. This shouldn't affect your interpreter loop, because the skip is effectively set after the branch when you call EXECF. But now you don't need caveats like you describe above. Is it as flexible? No, but it's much safer for what is likely to be the most common use cases.

    Edit: Also, couldn't you use the CZ flags here?

    * Use C (or Z) to indicate slow or fast skipping
    * You can then combine SKIP and SKIPF
    * Add the JMP (or CALL) variant
  • Seairth,
    The instruction slots he's using for them already have CZ forced to 0. So he can't use the CZ.
  • SeairthSeairth Posts: 2,474
    edited 2017-03-24 18:17
    Roy Eltham wrote: »
    Seairth,
    The instruction slots he's using for them already have CZ forced to 0. So he can't use the CZ.

    Yes, but are the forced zeros necessary, or did he just set them to zero because he had no use for them? Or it might be he just can't do that for opcode 1101011.

    Still, I figured it was worth at least suggesting it...
  • jmgjmg Posts: 15,140
    cgracey wrote: »
    I was testing SKIP between cog and hub modes around REP and I realized that we need different types of SKIPs. We need one that cancels single instructions, for use anywhere, and we need another that does the fast skipping in cog memory. The fast skipping doesn't work as simply around branches as the single-SKIP does.
    Cool. I was thinking two SKIPs could solve some issues, but was reticent about suggesting another opcode change.....
    cgracey wrote: »
    SKIP works everywhere and is completely sane. It can work inside of REP, too. It just cancels instructions as they come up, per the SKIP pattern.

    Portable and edit friendly, all sounding great....
    cgracey wrote: »
    SKIPF is the fast version for use inside cog memory. Any branch instructions allowed for will need to have another "0" bit to backstop the "1"-series reduction. In other words, if you have a "0" where a branch is, you'll need another "0" after that, and conform to the allowance.
    Given the restrictions and differing timing, the SKIPF may be better renamed HOPG (as in HOPcoG or HOPCOG) ?
    The tools can now also check this special opcode is only used in COG memory zones.
    cgracey wrote: »
    EXECF is the instruction that jumps to D[9:0] and sets a SKIPF pattern of D[31:10].
    Is this a 'jump with short parameter', and it is not limited to use with SKIP, or is a SKIPF encapsulated in this opcode ?
    In the latter case, the wording would maybe be better as ?
    EXECF is the instruction that jumps to D[9:0] and executes a SKIPF pattern of D[31:10].
  • cgraceycgracey Posts: 14,133
    Seairth wrote: »
    Roy Eltham wrote: »
    Seairth,
    The instruction slots he's using for them already have CZ forced to 0. So he can't use the CZ.

    Yes, but are the forced zeros necessary, or did he just set them to zero because he had no use for them? Or it might be he just can't do that for opcode 1101011.

    Still, I figured it was worth at least suggesting it...

    They don't need to be 0's. They could be C and Z, but then we start affecting flags.
  • cgraceycgracey Posts: 14,133
    The reason EXECF doesn't do a CALL is because it's better to be able to return to an arbitrary address than the next address. By pre-stuffing the stack with the interpreter loop address, we can get automatic returns to the top of the loop, not just to the next instruction which would usually need to jump back to the loop, anyway.
  • cgraceycgracey Posts: 14,133
    jmg wrote: »
    Cool. I was thinking two SKIPs could solve some issues, but was reticent about suggesting another opcode change.....

    I was, too, but we just need different types of SKIPs.
    Is this a 'jump with short parameter', and it is not limited to use with SKIP, or is a SKIPF encapsulated in this opcode ?
    In the latter case, the wording would maybe be better as ?
    EXECF is the instruction that jumps to D[9:0] and executes a SKIPF pattern of D[31:10].

    It's the latter case. I'll word it as you say.
  • cgraceycgracey Posts: 14,133
    Okay. I really got into the whole SKIP/SKIPF/EXECF Verilog code and re-thought it out with every detail in mind.

    It's working a lot better now. SKIP and SKIPF both work with branches in a consistent manner. In the prior version, I had some logic problems. There's no longer any need to place '0' bits after branch positions in the SKIPF data. This is much better. Everything tests out fine.

    I'm doing a compile for the Prop123_A9 now. I'll get an FPGA update out ASAP.
  • Nice work Chip. Sorting this feature out is worth it.

    Hey, maybe we are getting good on instructions now. Here's to hoping.

    Got my FPGA all setup and waiting. :D
  • RaymanRayman Posts: 13,800
    I suppose the downside to this (sorry) is that GCC is unlikely to use any of these new instructions, right?

    So, we may be delaying rollout for a small fraction of potential users....
  • Rayman wrote: »
    I suppose the downside to this (sorry) is that GCC is unlikely to use any of these new instructions, right?

    So, we may be delaying rollout for a small fraction of potential users....

    I wouldn't say that. For instance, I only use PASM and Spin on the P1 (haven't even tried C/C++ on it yet). I suspect there are quite a few people in that category. And those people will benefit quite a bit from having a fast spin interpreter for the P2.
  • cgraceycgracey Posts: 14,133
    I've got the Prop123_A9 and BeMicro_A9 compiles done. Compiling for the Prop123_A7 now.
Sign In or Register to comment.