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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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...
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.....
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.
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].
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.
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.
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].
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.
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.
Comments
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.
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
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.
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.
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.
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
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.
Here are the instructions now:
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
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...
Portable and edit friendly, all sounding great....
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.
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].
They don't need to be 0's. They could be C and Z, but then we start affecting flags.
I was, too, but we just need different types of SKIPs.
It's the latter case. I'll word it as you say.
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.
Hey, maybe we are getting good on instructions now. Here's to hoping.
Got my FPGA all setup and waiting.
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.