I guess I don't understand debugging/interrupts...
What happens if I fail to set the interrupt vectors?
When a cog starts executing user code, a debug interrupt immediately occurs and the cog jumps to where its INA's shadow register points. The tiny cog-startup ROM in the cog sets that pointer to $400+cogid*4. There needs to be some instruction there to receive the branch. If you want to debug, make it a JMP to somewhere. If you want it to immediately release and not come back, make it an RETI0.
Chip,
Can this behavior be turned on by a bit in COGINIT like the start in hubexec bit?
It could be, but that would mean interfering with the code base, somewhat. The way it is now, you could practically debug an entire application without getting into the target code.
Chip
I have the following hub code which produces this error
orgh $2000
go mov p2pa_mode,#0
jmp @go2 '<-- Error '"Relative addresses cannot cross between cog and hub domains."
go1 mov p2pa_mode,#1
go2 mov reg0,adra 'save adra
What am I missing here?
Edit: I replaced all my relative jmp/call references in my hub code for absolute and all working now.
It seems Pnut doesn't like relative addresses in Hub code?
Chip
I have the following hub code which produces this error
orgh $2000
go mov p2pa_mode,#0
jmp @go2 '<-- Error '"Relative addresses cannot cross between cog and hub domains."
go1 mov p2pa_mode,#1
go2 mov reg0,adra 'save adra
What am I missing here?
Edit: I replaced all my relative jmp/call references in my hub code for absolute and all working now.
It seems Pnut doesn't like relative addresses in Hub code?
My error. I had put that check into the assembler, but forgot to limit it to the second pass. I'm posting a "B" version now at the top of this thread. Thanks for pointing this out.
Along the idea of adding a bit for the debug ability, couldn't that just prevent/mask the debug interrupt? I'm thinking something like:
D/# : %x_xdhN_nnnn
xx : not used (yet )
d : 0 = normal operation, 1 = debug interrupt (working as you describe above)
h : 0 = load cog from PTRB and start at $0, 1 = JMP to PTRB
N : 0 = init cog nnnn, 1 = init next available cog (nnnn ignored)
nnnn: cog number to use when N=0
(note: I'm guessing that S/# is stored in PTRB on coginit?)
These 16 debug interrupt instructions at $400 allow for NSA-style complete interdiction of all cog execution. It's scary! It has a price, though: Your freedom to do whatever you want with hub memory. This is the debug solution for our brave new world. We could make it work on a per-cog basis, but why bother? That'd be like getting warrants, or something. What do you guys want? Are you willing to give up a little freedom here? Are you wondering if you even have a choice?
These 16 debug interrupt instructions at $400 allow for NSA-style complete interdiction of all cog execution. It's scary! It has a price, though: Your freedom to do whatever you want with hub memory. This is the debug solution for our brave new world. We could make it work on a per-cog basis, but why bother? That'd be like getting warrants, or something. What do you guys want? Are willing to give up a little freedom here? Are you wondering if you even have a choice?
Well, here's the thing. If I wanted to debug code loaded in the cog, couldn't I get the same effect by defining a debug_start routine in hub memory that would:
1. Copy $1F8 longs to cog memory
2. Set the debug address (in INA shadow register)
3. set the debug breakpoint to the start address
4. JMP to start address
Then, whenever I want to debug a cog, I coginit cog_num, @debug_start. Wouldn't this give me the same result as what you have? Similarly, if I want to debug hub code, wouldn't the process be the same as above, except step 1?
(note: yes, I would somehow need to pass the start address, but I could use the same registers you are using in your scheme. only, in my case, I can organize those wherever I want. Or use a stack. Or whatever.)
These 16 debug interrupt instructions at $400 allow for NSA-style complete interdiction of all cog execution. It's scary! It has a price, though: Your freedom to do whatever you want with hub memory. This is the debug solution for our brave new world. We could make it work on a per-cog basis, but why bother? That'd be like getting warrants, or something. What do you guys want? Are willing to give up a little freedom here? Are you wondering if you even have a choice?
Well, here's the thing. If I wanted to debug code loaded in the cog, couldn't I get the same effect by defining a debug_start routine in hub memory that would:
1. Copy $1F8 longs to cog memory
2. Set the debug address (in INA shadow register)
3. set the debug breakpoint to the start address
4. JMP to start address
Then, whenever I want to debug a cog, I coginit cog_num, @debug_start. Wouldn't this give me the same result as what you have? Similarly, if I want to debug hub code, wouldn't the process be the same as above, except step 1?
(note: yes, I would somehow need to pass the start address, but I could use the same registers you are using in your scheme. only, in my case, I can organize those wherever I want. Or use a stack. Or whatever.)
That would work, of course. It would necessitate changing the code, though.
The way it is now with these vectors, you could debug whatever cog you wanted, without needing to get deep into what might be some indirect COGINIT setup. All you'd need to know is the cog number, and you could do it. It might be an interesting way to trap all kinds of profiling data with no cog being the wiser. It's really like the NSA now.
What if you make the debug interrupt global to all cogs? Then there would be only one long lost of hubram, and maybe it could be moved out of hubram into some global hub register. If you want debug only some cogs, then your debug handler could just immediately RETI0 when it gets run on cogs you don't want to debug.
Another big advantage of this is that you won't have to tell coginit which cog to use if you want to use debugging - you can let it start whichever cog it likes via D[4], and then have the debug interrupt handler look at ptrb and see whether or not the code should be debugged or if it should just immediately RETI0.
What if you make the debug interrupt global to all cogs?
Err, would that not mean, you cannot debug more than 1 cog ?
It would mean that the debug ISR would have to determine which cog he is and branch, again, to the appropriate handler.
I've just been playing around with this tonight and it is very powerful. It really is like the NSA. You can trap every cog starting up, and maintain a little database of what cog was started when, at what address, and then poll them to find out what they are doing, later. Imagine being able to just get a snapshot of any cog, at any time, with no setup, aside from the code monkeying with the vectors and some debug workspace. It's pretty wild! No need to plant hooks in your code, either. It just works.
What if you make the debug interrupt global to all cogs?
Err, would that not mean, you cannot debug more than 1 cog ?
It would mean that the debug ISR would have to determine which cog he is and branch, again, to the appropriate handler.
I've just been playing around with this tonight and it is very powerful. It really is like the NSA. You can trap every cog starting up, and maintain a little database of what cog was started when, at what address, and then poll them to find out what they are doing, later. Imagine being able to just get a snapshot of any cog, at any time, with no setup, aside from the code monkeying with the vectors and some debug workspace. It's pretty wild! No need to plant hooks in your code, either. It just works.
You sound pretty excited about this Chip so I am certainly intrigued enough to start playing with it as soon as I'm done with getting my software back to the point it was with the previous FPGA. Once I have an interactive environment running I will start to have some fun with this "debug" method.
Chip
I'm still getting the same error as above with the "B" version of Pnut.
I just downloaded from the new link and it is the new version. I verified I can do @ branches in hub space.
Are you sure you didn't mix up the old and new files, somehow?
Chip
I thought I made the mistake of running the old version but I am running the correct version.
I think Pnut is Ok now.
I am getting the same error but this time they are "real" and I am changing some of my relative jumps to absolute.
My code doesn't work anymore so it needs some tweaks to fit the new changes.
On the subject of Pnut version and FPGA image version, is it possible for the info dialog in pnut to reflect its real version and the required matching FPGA image version. The info dialog is the same as it was in all the P2-Hot pnut versions.
As this code is... cogs 2 and 3 blink at one hz and cog0 lights up but doesn't blink, but if I uncomment the ' djnz cognum,@:loop, it blinks at the same rate as cogs 2 and 3. So, if the djnz is in there, the cog0 falls through, but if there is no djnz, it doesn't?
con
myval = 25_000_000
dat
orgh 0
'
'launch cogs #2,#3
'look at effect of djnz
org
:loop
' djnz cognum,@:loop
coginit #2,#@blink
coginit #3,#@blink
cognum long 1
'
' blink
org
blink cogid x 'which cog am I?
setb dirb,x 'make that pin an output
notb outb,x 'flip its output state
waitx ##myval 'wait that many clocks
jmp @blink 'do it again
x res 1 'variable at cog register 8
' Cog 0..15 initial debug interrupt vectors
'
orgh $400
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
reti0
Looks like you posted the wrong code as there isn't anything in :loop. However you need djns so that when there is a coginit in the loop it also executes for cog 0 which is also the one running the loop so that finally it never exits the djns loop since it has been coginit'd. Otherwise your code is falling through to the cognum as if it were an instruction. I think that's correct.
Chip
I'm still getting the same error as above with the "B" version of Pnut.
I just downloaded from the new link and it is the new version. I verified I can do @ branches in hub space.
Are you sure you didn't mix up the old and new files, somehow?
Chip
I thought I made the mistake of running the old version but I am running the correct version.
I think Pnut is Ok now.
I am getting the same error but this time they are "real" and I am changing some of my relative jumps to absolute.
My code doesn't work anymore so it needs some tweaks to fit the new changes.
On the subject of Pnut version and FPGA image version, is it possible for the info dialog in pnut to reflect its real version and the required matching FPGA image version. The info dialog is the same as it was in all the P2-Hot pnut versions.
Could you post a snippet of code that is failing?
Good idea about starting to use version numbers. I'll do that.
P.S. I understand now that PNut is okay, after all. I just didn't read carefully enough the first time.
I am trying to get Tachyon to compile and work properly but so far no joy. The compiler is touchy about the position of the intvecs, as it often says "Hub origin already exceeds target" or I get an error on coginit source of "constant must be from 0 to 511". I guess I am not quite fully understanding all the orgs and orghs and how they affect the compiler itself. I chopped out most of the code but unless I have a small program I get an error.
Can you confirm that the special registers are back at the top of cog ram.
The reason that 2nd ORG wasn't working was because it was only setting the cog origin, and not advancing within the hub image. use ORGF $100 to fill to cog $100, so that things are properly positioned.
There is another problem that I totally didn't anticipate. When you get to $100 in your cog image, beginning from hub $00000, you are already at $400! We need to change some things around.
Neither seems that great, do they? What to do here?
Having these debug hooks SOMEWHERE provides a lot of surprising capabilities. It almost seems like cog exec and lut exec space should move to the END of hub RAM, as that will be where data wants to live, normally, trailing all executable code. Nobody will be inclined to put code there, I think, so it's useful for cog/lut exec space.
What if...
hub $00000..$0003F = cog r/w event 16 longs (already the case, but currently covered by initial cog image)
hub $00040..$0007F = initial debug interrupt instructions (16 RETI0s/JMPs)
hub $00080+ = initial cog image
hub $00000..$FFBFF = hub exec range
hub $FFC00..$FFDFF = lut exec range (notice that lut-to-cog exec potential)
hub $FFE00..$FFFFF = cog exec range
I don't how to make this look pretty, but there may be a simple way. Actually ORG would take care of this.
Importantly, this makes all lower memory just RAM, with the first 32 longs serving some fixed purposes. This moves cog/lut exec addresses to the hinterlands, where nobody probably cares about placing code, as it is the domain of large data buffers. This makes a lot of sense, I think.
Comments
What happens if I fail to set the interrupt vectors?
Am I see this:
ROM bootloader loads cog0 with HUB RAM from $000 to $3FF and then executes from cog address 0?
Somehow coginit is reading hub longs at $400 to set debug info?
When a cog starts executing user code, a debug interrupt immediately occurs and the cog jumps to where its INA's shadow register points. The tiny cog-startup ROM in the cog sets that pointer to $400+cogid*4. There needs to be some instruction there to receive the branch. If you want to debug, make it a JMP to somewhere. If you want it to immediately release and not come back, make it an RETI0.
Can this behavior be turned on by a bit in COGINIT like the start in hubexec bit?
If a COGINIT has D[5] clear, $1F8 longs are loaded from hub @PTRB into cog registers $1F0..$1F8 and a JMP to $000 executes.
If a COGINIT has D[5] set, a JMP to PTRB executes.
It could be, but that would mean interfering with the code base, somewhat. The way it is now, you could practically debug an entire application without getting into the target code.
We need to figure out where to inject this functionality, if not at the outermost level.
I hate to sound negative, btw, grateful for the updated files
BTW: I think I like the addition of interrupts and debugging. But, I'd rather that it didn't interfere in any way with usage without those things...
I have the following hub code which produces this error What am I missing here?
Edit: I replaced all my relative jmp/call references in my hub code for absolute and all working now.
It seems Pnut doesn't like relative addresses in Hub code?
My error. I had put that check into the assembler, but forgot to limit it to the second pass. I'm posting a "B" version now at the top of this thread. Thanks for pointing this out.
Along the idea of adding a bit for the debug ability, couldn't that just prevent/mask the debug interrupt? I'm thinking something like:
D/# : %x_xdhN_nnnn
xx : not used (yet )
d : 0 = normal operation, 1 = debug interrupt (working as you describe above)
h : 0 = load cog from PTRB and start at $0, 1 = JMP to PTRB
N : 0 = init cog nnnn, 1 = init next available cog (nnnn ignored)
nnnn: cog number to use when N=0
(note: I'm guessing that S/# is stored in PTRB on coginit?)
Well, here's the thing. If I wanted to debug code loaded in the cog, couldn't I get the same effect by defining a debug_start routine in hub memory that would:
1. Copy $1F8 longs to cog memory
2. Set the debug address (in INA shadow register)
3. set the debug breakpoint to the start address
4. JMP to start address
Then, whenever I want to debug a cog, I coginit cog_num, @debug_start. Wouldn't this give me the same result as what you have? Similarly, if I want to debug hub code, wouldn't the process be the same as above, except step 1?
(note: yes, I would somehow need to pass the start address, but I could use the same registers you are using in your scheme. only, in my case, I can organize those wherever I want. Or use a stack. Or whatever.)
That would work, of course. It would necessitate changing the code, though.
The way it is now with these vectors, you could debug whatever cog you wanted, without needing to get deep into what might be some indirect COGINIT setup. All you'd need to know is the cog number, and you could do it. It might be an interesting way to trap all kinds of profiling data with no cog being the wiser. It's really like the NSA now.
I'm still getting the same error as above with the "B" version of Pnut.
I just downloaded from the new link and it is the new version. I verified I can do @ branches in hub space.
Are you sure you didn't mix up the old and new files, somehow?
Another big advantage of this is that you won't have to tell coginit which cog to use if you want to use debugging - you can let it start whichever cog it likes via D[4], and then have the debug interrupt handler look at ptrb and see whether or not the code should be debugged or if it should just immediately RETI0.
Err, would that not mean, you cannot debug more than 1 cog ?
It would mean that the debug ISR would have to determine which cog he is and branch, again, to the appropriate handler.
I've just been playing around with this tonight and it is very powerful. It really is like the NSA. You can trap every cog starting up, and maintain a little database of what cog was started when, at what address, and then poll them to find out what they are doing, later. Imagine being able to just get a snapshot of any cog, at any time, with no setup, aside from the code monkeying with the vectors and some debug workspace. It's pretty wild! No need to plant hooks in your code, either. It just works.
You sound pretty excited about this Chip so I am certainly intrigued enough to start playing with it as soon as I'm done with getting my software back to the point it was with the previous FPGA. Once I have an interactive environment running I will start to have some fun with this "debug" method.
Chip
I thought I made the mistake of running the old version but I am running the correct version.
I think Pnut is Ok now.
I am getting the same error but this time they are "real" and I am changing some of my relative jumps to absolute.
My code doesn't work anymore so it needs some tweaks to fit the new changes.
On the subject of Pnut version and FPGA image version, is it possible for the info dialog in pnut to reflect its real version and the required matching FPGA image version. The info dialog is the same as it was in all the P2-Hot pnut versions.
Could you post a snippet of code that is failing?
Good idea about starting to use version numbers. I'll do that.
P.S. I understand now that PNut is okay, after all. I just didn't read carefully enough the first time.
Here's a test version that worked fine on the last version of the FPGA and PNut.
There seems to be an issue with the ORG directive
If I try to place my register at any nominated cog address the program fails.
Can you confirm that the special registers are back at the top of cog ram.
I thought RJMPs could go from anywhere, to anywhere ?
(just like AJMPs)
The reason that 2nd ORG wasn't working was because it was only setting the cog origin, and not advancing within the hub image. use ORGF $100 to fill to cog $100, so that things are properly positioned.
There is another problem that I totally didn't anticipate. When you get to $100 in your cog image, beginning from hub $00000, you are already at $400! We need to change some things around.
Either...
hub $00000..$007FF = cog image
hub $00800..$0083F = debug vectors
...or...
hub $00400..$0043F = debug vectors (lowest possible hub-exec addresses)
hub $00800..$00FFF = cog image
Neither seems that great, do they? What to do here?
Having these debug hooks SOMEWHERE provides a lot of surprising capabilities. It almost seems like cog exec and lut exec space should move to the END of hub RAM, as that will be where data wants to live, normally, trailing all executable code. Nobody will be inclined to put code there, I think, so it's useful for cog/lut exec space.
What if...
hub $00000..$0003F = cog r/w event 16 longs (already the case, but currently covered by initial cog image)
hub $00040..$0007F = initial debug interrupt instructions (16 RETI0s/JMPs)
hub $00080+ = initial cog image
hub $00000..$FFBFF = hub exec range
hub $FFC00..$FFDFF = lut exec range (notice that lut-to-cog exec potential)
hub $FFE00..$FFFFF = cog exec range
I don't how to make this look pretty, but there may be a simple way. Actually ORG would take care of this.
Importantly, this makes all lower memory just RAM, with the first 32 longs serving some fixed purposes. This moves cog/lut exec addresses to the hinterlands, where nobody probably cares about placing code, as it is the domain of large data buffers. This makes a lot of sense, I think.