You're right that for constant jumps and calls the assembler can know if it's going to hub from cog, to cog from hub, or staying in the cog or hub. This could get rid of the "_" versions of branches.
We could have either toggling and non-toggling branches, or fixed cog and fixed hub branches. The latter seems simpler, but will inhibit code from working in both cog and hub. There's also the issue of the 9-bit constant branches (DJNZ, etc.) needing to work in both cog and hub. For these reasons, I think a toggling system is better, regardless of the syntax.
I thought the 9 bit constants in DJNZ instructions were going to be treated as relative addresses? In that case they just stay in the mode they're currently in.
I updated my previous post with this table of variants
COG-COG COG-HUB HUB-COG HUB-HUB
ABS #IMM @REG #IMM @REG #IMM @REG #IMM @REG
REL #IMM @REG ???? ???? ???? ???? #IMM @REG
ABS call CALL call_ CALL_ call_ CALL_ call CALL
REL call na call_ na call_ na call na
I cannot see any reason for:
COG-HUB and HUB-COG Relative instructions, either #Immediate or @Register
I see little use to have:
COG-COG @Register Relative
HUB-HUB @Register Relative
The advantage of the toggling/non toggling JUMP versions is that you can execute the same binary code in HUB mode and in Cog mode.
The Cog code is anyway generated as an image in Hub-Memory before it is loaded into the cog. It may be useful to be able to execute the code in the image also in hub mode.
With JMP and HJMP you will need to change all the jumps in a code snippet if you decide to execute it in the other mode.
If the compiler generates two different instructions from the same mnemonic depending on the Hub or cog mode it's a bit simpler, but you can not execute the same binary code in both modes. This is only possible with toggling the mode on CPU level.
You're right that for constant jumps and calls the assembler can know if it's going to hub from cog, to cog from hub, or staying in the cog or hub. This could get rid of the "_" versions of branches.
We could have either toggling and non-toggling branches, or fixed cog and fixed hub branches. The latter seems simpler, but will inhibit code from working in both cog and hub. There's also the issue of the 9-bit constant branches (DJNZ, etc.) needing to work in both cog and hub. For these reasons, I think a toggling system is better, regardless of the syntax.
Actually, treating the 17th bit (the one you currently use to distinguish JMP from JMP_) as an extra address bit would solve your problem of code working in both cog and hub mode because the assembler symbol table would know which memory space a symbol was in and set the bit appropriately. If you move the code to the other space (hub to cog for instance), then the address space of the labels would also change and the code would continue to work. Your scheme with toggle breaks down if you move code from one space to the other but don't also move all of the labels it references as well. Say for example your code is in COG space and contains a JMP_ to a location in hub space. If you move that instruction to hub space then JMP_ will toggle to COG space and reference the wrong address. This is fixed by using that extra bit as a COG vs. hub selector.
The advantage of the toggling/non toggling JUMP versions is that you can execute the same binary code in HUB mode and in Cog mode.
The Cog code is anyway generated as an image in Hub-Memory before it is loaded into the cog. It may be useful to be able to execute the code in the image also in hub mode.
With JMP and HJMP you will need to change all the jumps in a code snippet if you decide to execute it in the other mode.
If the compiler generates two different instructions from the same mnemonic depending on the Hub or cog mode it's a bit simpler, but you can not execute the same binary code in both modes. This is only possible with toggling the mode on CPU level.
Andy
I think there are other problems with executing code from both hub and COG mode as I mentioned in my earlier post. Also, it doesn't seem like it would be useful enough to justify the awkward toggle semantics.
The advantage of the toggling/non toggling JUMP versions is that you can execute the same binary code in HUB mode and in Cog mode.
The Cog code is anyway generated as an image in Hub-Memory before it is loaded into the cog. It may be useful to be able to execute the code in the image also in hub mode.
With JMP and HJMP you will need to change all the jumps in a code snippet if you decide to execute it in the other mode.
If the compiler generates two different instructions from the same mnemonic depending on the Hub or cog mode it's a bit simpler, but you can not execute the same binary code in both modes. This is only possible with toggling the mode on CPU level.
Andy
Andy,
Sorry, I think with the restrictions and caveats, running code compiled for cog and running it in hub or visa versa is just asking for some unseen trouble.
Toggling vs Direct:
The instruction bit just gets used instead of a "toggle" bit it is used as a set/reset bit. The flipflop in the ALU/Pipeline just gets set/reset instead of toggled.
The DJNZ etc instructions just use the bit in the ALU/Pipeline as is, and no change.
The instructions JMP/CALL become goto/stayin COG mode, and JMP_/CALL_ become goto/stayin HUB mode (could be called HJMP/HCALL if required, but as I said, the compiler can take care of this automatically).
This just seems so much cleaner to me, and currently I cannot see any reason in favour of the toggle. Chip, am I really missing something here??? I definitely don't want to see anyone thinking they can run compiled code from either cog or hub as I really think that is a certain recipe for disaster.
Actually, treating the 17th bit (the one you currently use to distinguish JMP from JMP_) as an extra address bit would solve your problem of code working in both cog and hub mode because the assembler symbol table would know which memory space a symbol was in and set the bit appropriately. If you move the code to the other space (hub to cog for instance), then the address space of the labels would also change and the code would continue to work. Your scheme with toggle breaks down if you move code from one space to the other but don't also move all of the labels it references as well. Say for example your code is in COG space and contains a JMP_ to a location in hub space. If you move that instruction to hub space then JMP_ will toggle to COG space and reference the wrong address. This is fixed by using that extra bit as a COG vs. hub selector.
If relative addressing is used, code will work in both places.
I think that absolute addressing has to be something explicit, maybe indicated with #, as it is at the moment. Relative branches are using @, but it would be neat to make that implied.
Toggling vs Direct:
The instruction bit just gets used instead of a "toggle" bit it is used as a set/reset bit. The flipflop in the ALU/Pipeline just gets set/reset instead of toggled.
The DJNZ etc instructions just use the bit in the ALU/Pipeline as is, and no change.
The instructions JMP/CALL become goto/stayin COG mode, and JMP_/CALL_ become goto/stayin HUB mode (could be called HJMP/HCALL if required, but as I said, the compiler can take care of this automatically).
This just seems so much cleaner to me, and currently I cannot see any reason in favour of the toggle. Chip, am I really missing something here??? I definitely don't want to see anyone thinking they can run compiled code from either cog or hub as I really think that is a certain recipe for disaster.
Generally speaking, that would be disastrous, but I could see writing a block of code that could be called in the hub, or moved into the cog for really fast execution.
This whole thing is a little tricky to think about because there are syntax issues involved, too.
Generally speaking, that would be disastrous, but I could see writing a block of code that could be called in the hub, or moved into the cog for really fast execution.
This whole thing is a little tricky to think about because there are syntax issues involved, too.
I'm signing off for the evening. I suppose this will all have been decided by the time I wake up again. Good luck in sorting this out! And I'll make one final plea for explicit selection of the target address space rather than toggling between address spaces. Good night....
I'm signing off for the evening. I suppose this will all have been decided by the time I wake up again. Good luck in sorting this out! And I'll make one final plea for explicit selection of the target address space rather than toggling between address spaces. Good night....
I started out thinking the same thing, but as I got to considering the mnemonic names I realized that it was going to be a pain to write one kind of code with JMP and another kind with HJMP. I wanted to make the differences go away to keep code simple. Still more to think about....
...
I think that absolute addressing has to be something explicit, maybe indicated with #, as it is at the moment. Relative branches are using @, but it would be neat to make that implied.
Chip,
This goes against common usage, where @ is used to denote indirection.
Here seems to be the current combination/requirement???
@reg uses a register for Absolute and Indirection
#Imm could be used for Immediate Absolute (as we do in the P1, but I causes a lot of confusion)
label could be used for Immediate Relative (new - but in most cases if the # is left out, this will still work - unless self-modifying code is used)
I started out thinking the same thing, but as I got to considering the mnemonic names I realized that it was going to be a pain to write one kind of code with JMP and another kind with HJMP. I wanted to make the differences go away to keep code simple. Still more to think about....
If HJMP or whatever makes your pnut task simpler, do that. Op names can be changed simply later on when there is more time or the open compiler is made to run on P2.
Chip,
For HUB code, I would even be happy to just compile it as if it were cog code (like I do with LMM now) and hand code a long for the appropriate JMP/CALLs.
May just need something like
CON
HJMP EQU %1111101_100_0000_xx_0000000000000000
_IF_Z_OR_C EQU %xxxx << 18
DAT
ORG 0
ORGH $4000
...code here...
LONG _IF_Z_OR_C I HJMP | ~label ' if_z_or_c hjmp #label
[code]
where ~label would be some char and the label would be the hub or cog address - hopefully you could add this feature to pnut as a temp thing???
Postedit: Maybe
LONG _IF_Z_OR_C | HJMP | @label
or @@label
would already work???
I wonder a bit what you all find so dangerous or complicated with toggling jumps.
I find it not more complicated to read in a code than having two times the same mnemonic which generates different binary code depending of the mode.
I can't really estimate how difficult or useful the toggling version will be, but it allows definitly more tricks, and simplifies the Assembler a bit (no directives for Hub / Cog mode).
If we have separate hub and cog jumps then the 16 bit immediate addresses in the cog-jumps make not much sense. We may just waste these bits or Chip has to change the whole instruction set again.
I don't vote for one or the other version, I just don't see a big problem with toggling. I will take what I get...
Defintely prefer the existing P1 "#" sign for immediate. It is confusing, but it's also consistent with a lot of other uses. Seems a PITA to change it now.
I just realized that since all hub-to-cog and cog-to-hub constant jumps must be absolute (since relative addresses make no sense), there is a already an obvious way of discriminating where you are going:
Absolute addresses $000..$1FF are valid cog addresses, but are ROM in hub memory, so not practically called as hub addresses. These would obviously be cog addresses.
Absolute addresses $200..$FFFF are obviously hub addresses, as they are outside the range of cog memory.
So, that takes care of all constant absolute JMPs and CALLs within and between cog and hub memory.
What's left is the register-based JMPs and CALLs, which are always absolute. Their ranges could be discriminated at execution time to determine where they were headed.
This just leaves constant relative branches, which don't ever change modes, and therefore require no special consideration.
All this means that we don't need the JMP_/CALL_ instructions, at all, but we can let the hardware figure out at execution time what the deal is.
Does anyone see any problems with this?
(Perhaps it's providence that the ROM starts at $00000 and is >= $200 longs!)
I just realized that since all hub-to-cog and cog-to-hub constant jumps must be absolute (since relative addresses make no sense), there is a already an obvious way of discriminating where you are going:
Absolute addresses $000..$1FF are valid cog addresses, but are ROM in hub memory, so not practically called as hub addresses. These would obviously be cog addresses.
Absolute addresses $200..$FFFF are obviously hub addresses, as they are outside the range of cog memory.
So, that takes care of all constant absolute JMPs and CALLs within and between cog and hub memory.
What's left is the register-based JMPs and CALLs, which are always absolute. Their ranges could be discriminated at execution time to determine where they were headed.
This just leaves constant relative branches, which don't ever change modes, and therefore require no special consideration.
All this means that we don't need the JMP_/CALL_ instructions, at all, but we can let the hardware figure out at execution time what the deal is.
Does anyone see any problems with this?
(Perhaps it's providence that the ROM starts at $00000 and is >= $200 longs!)
Nice Job!
Postedit: The more I think about it, the more elegant it becomes! Frees up instruction space, no toggling instructions, and simpler for the compiler too!
BTW It's $200 << 2 = $800, but that's still fine as ROM < $E00
Yes, I use the fact that cog <$200 in my P2 Debugger when the user enters an address. I just let them enter $2_0000_0000 to address the ROM (now will be $8_0000_0000).
I just realized that since all hub-to-cog and cog-to-hub constant jumps must be absolute (since relative addresses make no sense), there is a already an obvious way of discriminating where you are going:
Absolute addresses $000..$1FF are valid cog addresses, but are ROM in hub memory, so not practically called as hub addresses. These would obviously be cog addresses.
Absolute addresses $200..$FFFF are obviously hub addresses, as they are outside the range of cog memory.
So, that takes care of all constant absolute JMPs and CALLs within and between cog and hub memory.
What's left is the register-based JMPs and CALLs, which are always absolute. Their ranges could be discriminated at execution time to determine where they were headed.
This just leaves constant relative branches, which don't ever change modes, and therefore require no special consideration.
All this means that we don't need the JMP_/CALL_ instructions, at all, but we can let the hardware figure out at execution time what the deal is.
Does anyone see any problems with this?
(Perhaps it's providence that the ROM starts at $00000 and is >= $200 longs!)
Chip
Perhaps I'm loosing something, due to sleeplessness, but anyway....
How could then we craft a CALL or JUMP, to take advantage of any HUB ROM resident routine, whose addresses are in the range &00000 - $001FF?
Chip,
While you are changing the instructions for these simpler JMP/CALLs,
Might it be worthwhile to move the REPD instruction down to S=%010iiiiii (or %100iiiiii, or even share the REPS instruction for the loss of a bit on the REPS instruction), and move the instructions from %01xxxxxxx onwards into the space freed up by moving REPD down? Just a thought.
Perhaps I'm loosing something, due to sleeplessness, but anyway....
How could then we craft a CALL or JUMP, to take advantage of any HUB ROM resident routine, whose addresses are in the range &00000 - $001FF?
Yanomani
You couldn't. But what's there are cog programs that run in cogs, so they're not callable. However, it might be good to swap locations of the ROM SHA256 and ROM MONITOR so that the SHA256 could be hub-callable routines, instead of a cog program. It would just have to start above $00800 ($200 long address). That way, you could call it from the cog that needs it, rather than keeping it a stand-along program that needs a whole cog to run. The ROM MONITOR, on the other hand, is a complete program that must run in a cog. If it turns out to have any useful routines, they could be put into ROM and made callable, so that others could use them, too.
Edit: We could have entry points at $200+ (long address) which could do relative jumps backwards into the lower area, without causing things to switch to cog mode.
Perhaps I'm loosing something, due to sleeplessness, but anyway....
How could then we craft a CALL or JUMP, to take advantage of any HUB ROM resident routine, whose addresses are in the range &00000 - $001FF?
Yanomani
Sorry, we don't. But it's a small price to pay for such an elegant and simple solution. (and its $00000-$007FF)
Chip,
While you are changing the instructions for these simpler JMP/CALLs,
Might it be worthwhile to move the REPD instruction down to S=%010iiiiii (or %100iiiiii, or even share the REPS instruction for the loss of a bit on the REPS instruction), and move the instructions from %01xxxxxxx onwards into the space freed up by moving REPD down? Just a thought.
I just realized that since all hub-to-cog and cog-to-hub constant jumps must be absolute (since relative addresses make no sense), there is a already an obvious way of discriminating where you are going:
Absolute addresses $000..$1FF are valid cog addresses, but are ROM in hub memory, so not practically called as hub addresses. These would obviously be cog addresses.
Absolute addresses $200..$FFFF are obviously hub addresses, as they are outside the range of cog memory.
Sounds good, and common with how other micros manage things, so should be easy for new users to follow.
Edit: We could have entry points at $200+ (long address) which could do relative jumps backwards into the lower area, without causing things to switch to cog mode.
How large is the ROM now ? The useful stuff could go above $200, and the less useful / larger chunks could go < $200, which would reduce (or eliminate?) the number of double-hop calls to lower ROM ? (each one does cost RAM )
You couldn't. But what's there are cog programs that run in cogs, so they're not callable. However, it might be good to swap locations of the ROM SHA256 and ROM MONITOR so that the SHA256 could be hub-callable routines, instead of a cog program. It would just have to start above $00800 ($200 long address). That way, you could call it from the cog that needs it, rather than keeping it a stand-along program that needs a whole cog to run. The ROM MONITOR, on the other hand, is a complete program that must run in a cog. If it turns out to have any useful routines, they could be put into ROM and made callable, so that others could use them, too.
Edit: We could have entry points at $200+ (long address) which could do relative jumps backwards into the lower area, without causing things to switch to cog mode.
Sorry, we don't. But it's a small price to pay for such an elegant and simple solution. (and its $00000-$007FF)
Chip, Cluso99
Thanks for the prompt reply! At least I didn't got things confused, inside my brain!
There are a lot of lambs here, just waiting to skip some fences, and be accounted for. There are also a sheepdog, waiting to be called, to start its day journey.
As long as I don't start mixing things, lambs x cogs, skips x jumps, and calling sheepdogs, without waiting for their return, it's not yet the right time, to make an appointment with the family doctor.
Then there are those fences, lots of fences.... hhuuummm
Time to have a shower and a deep dive, towards bed!
Sounds good, and common with how other micros manage things, so should be easy for new users to follow.
How large is the ROM now ? The useful stuff could go above $200, and the less useful / larger chunks could go < $200, which would reduce (or eliminate?) the number of double-hop calls to lower ROM ? (each one does cost RAM )
The ROM goes to byte address $00DFF, so it is $E00 bytes long, or $380 longs long. That's 1.75 cog RAM's worth of data.
Comments
COG-HUB and HUB-COG Relative instructions, either #Immediate or @Register
I see little use to have:
COG-COG @Register Relative
HUB-HUB @Register Relative
This would reduce to:
The Cog code is anyway generated as an image in Hub-Memory before it is loaded into the cog. It may be useful to be able to execute the code in the image also in hub mode.
With JMP and HJMP you will need to change all the jumps in a code snippet if you decide to execute it in the other mode.
If the compiler generates two different instructions from the same mnemonic depending on the Hub or cog mode it's a bit simpler, but you can not execute the same binary code in both modes. This is only possible with toggling the mode on CPU level.
Andy
As 'JMP/CALL label' need both Relative and Absolute modes --->
How You will separate that?
And 'JMP/CALL @register' have usage as Relative and Absolute modes ---> In calculated JUMP tables
How You will separate that?
Sorry, I think with the restrictions and caveats, running code compiled for cog and running it in hub or visa versa is just asking for some unseen trouble.
The instruction bit just gets used instead of a "toggle" bit it is used as a set/reset bit. The flipflop in the ALU/Pipeline just gets set/reset instead of toggled.
The DJNZ etc instructions just use the bit in the ALU/Pipeline as is, and no change.
The instructions JMP/CALL become goto/stayin COG mode, and JMP_/CALL_ become goto/stayin HUB mode (could be called HJMP/HCALL if required, but as I said, the compiler can take care of this automatically).
This just seems so much cleaner to me, and currently I cannot see any reason in favour of the toggle. Chip, am I really missing something here??? I definitely don't want to see anyone thinking they can run compiled code from either cog or hub as I really think that is a certain recipe for disaster.
As Cluso said.
It is BAD idea to have code that are COG/HUB runnable.
As if anyone write Program code for HUB it will be mostly BIGGER programs that COG can handle.
If relative addressing is used, code will work in both places.
I think that absolute addressing has to be something explicit, maybe indicated with #, as it is at the moment. Relative branches are using @, but it would be neat to make that implied.
Generally speaking, that would be disastrous, but I could see writing a block of code that could be called in the hub, or moved into the cog for really fast execution.
This whole thing is a little tricky to think about because there are syntax issues involved, too.
I started out thinking the same thing, but as I got to considering the mnemonic names I realized that it was going to be a pain to write one kind of code with JMP and another kind with HJMP. I wanted to make the differences go away to keep code simple. Still more to think about....
This goes against common usage, where @ is used to denote indirection.
Here seems to be the current combination/requirement??? @reg uses a register for Absolute and Indirection
#Imm could be used for Immediate Absolute (as we do in the P1, but I causes a lot of confusion)
label could be used for Immediate Relative (new - but in most cases if the # is left out, this will still work - unless self-modifying code is used)
For HUB code, I would even be happy to just compile it as if it were cog code (like I do with LMM now) and hand code a long for the appropriate JMP/CALLs.
May just need something like
CON
HJMP EQU %1111101_100_0000_xx_0000000000000000
_IF_Z_OR_C EQU %xxxx << 18
DAT
ORG 0
ORGH $4000
...code here...
LONG _IF_Z_OR_C I HJMP | ~label ' if_z_or_c hjmp #label
[code]
where ~label would be some char and the label would be the hub or cog address - hopefully you could add this feature to pnut as a temp thing???
Postedit: Maybe
LONG _IF_Z_OR_C | HJMP | @label
or @@label
would already work???
I find it not more complicated to read in a code than having two times the same mnemonic which generates different binary code depending of the mode.
I can't really estimate how difficult or useful the toggling version will be, but it allows definitly more tricks, and simplifies the Assembler a bit (no directives for Hub / Cog mode).
If we have separate hub and cog jumps then the 16 bit immediate addresses in the cog-jumps make not much sense. We may just waste these bits or Chip has to change the whole instruction set again.
I don't vote for one or the other version, I just don't see a big problem with toggling. I will take what I get...
Andy
Defintely prefer the existing P1 "#" sign for immediate. It is confusing, but it's also consistent with a lot of other uses. Seems a PITA to change it now.
Absolute addresses $000..$1FF are valid cog addresses, but are ROM in hub memory, so not practically called as hub addresses. These would obviously be cog addresses.
Absolute addresses $200..$FFFF are obviously hub addresses, as they are outside the range of cog memory.
So, that takes care of all constant absolute JMPs and CALLs within and between cog and hub memory.
What's left is the register-based JMPs and CALLs, which are always absolute. Their ranges could be discriminated at execution time to determine where they were headed.
This just leaves constant relative branches, which don't ever change modes, and therefore require no special consideration.
All this means that we don't need the JMP_/CALL_ instructions, at all, but we can let the hardware figure out at execution time what the deal is.
Does anyone see any problems with this?
(Perhaps it's providence that the ROM starts at $00000 and is >= $200 longs!)
I think it is a beautiful solution.
edit: - and if you add ever add more cog ram to a P3xx then you may have more space for rom too...
Enjoy!
Mike
Postedit: The more I think about it, the more elegant it becomes! Frees up instruction space, no toggling instructions, and simpler for the compiler too!
BTW It's $200 << 2 = $800, but that's still fine as ROM < $E00
Yes, I use the fact that cog <$200 in my P2 Debugger when the user enters an address. I just let them enter $2_0000_0000 to address the ROM (now will be $8_0000_0000).
Chip
Perhaps I'm loosing something, due to sleeplessness, but anyway....
How could then we craft a CALL or JUMP, to take advantage of any HUB ROM resident routine, whose addresses are in the range &00000 - $001FF?
Yanomani
While you are changing the instructions for these simpler JMP/CALLs,
Might it be worthwhile to move the REPD instruction down to S=%010iiiiii (or %100iiiiii, or even share the REPS instruction for the loss of a bit on the REPS instruction), and move the instructions from %01xxxxxxx onwards into the space freed up by moving REPD down? Just a thought.
You couldn't. But what's there are cog programs that run in cogs, so they're not callable. However, it might be good to swap locations of the ROM SHA256 and ROM MONITOR so that the SHA256 could be hub-callable routines, instead of a cog program. It would just have to start above $00800 ($200 long address). That way, you could call it from the cog that needs it, rather than keeping it a stand-along program that needs a whole cog to run. The ROM MONITOR, on the other hand, is a complete program that must run in a cog. If it turns out to have any useful routines, they could be put into ROM and made callable, so that others could use them, too.
Edit: We could have entry points at $200+ (long address) which could do relative jumps backwards into the lower area, without causing things to switch to cog mode.
I'll look at that tonight and see.
Sounds good, and common with how other micros manage things, so should be easy for new users to follow.
How large is the ROM now ? The useful stuff could go above $200, and the less useful / larger chunks could go < $200, which would reduce (or eliminate?) the number of double-hop calls to lower ROM ? (each one does cost RAM )
Chip, Cluso99
Thanks for the prompt reply! At least I didn't got things confused, inside my brain!
There are a lot of lambs here, just waiting to skip some fences, and be accounted for. There are also a sheepdog, waiting to be called, to start its day journey.
As long as I don't start mixing things, lambs x cogs, skips x jumps, and calling sheepdogs, without waiting for their return, it's not yet the right time, to make an appointment with the family doctor.
Then there are those fences, lots of fences.... hhuuummm
Time to have a shower and a deep dive, towards bed!
Yanomani
The ROM goes to byte address $00DFF, so it is $E00 bytes long, or $380 longs long. That's 1.75 cog RAM's worth of data.