Examples of playing with COGINITs (P2-10-10-15 image)
mindrobots
Posts: 6,506
in Propeller 2
This is an example of everything I've been able to think of doing with COGINIT so far. The program is targeted for the 1-2-3 board but it only uses 8 cogs at most and keeps LEDs to less than 16, so I think it works on DE2 (I can test/verify at a later date). I've tried to filter out my dumb mistakes and misunderstandings. What I see as problems/concerns/gotchas are legitimate (I believe anyway).
Here's the code if you don't want to download and print to follow this:
General notes:
1) I was able to use "COGINIT #cog,#@target" UNTIL I moved the COGRAM sections (org 0) past the "orgh $1000", once I did this, I needed to use LOC and COGINIT as in the code above. When moved higher in hubram, you get the "exceeds 511" message. I understand this and understand why you need the LOC & COGINIT. It isn't a problem since usually your target will be in a higher address range - just use LOC & COGINIT all the time
2) There are also some variable initialization issues when running in HUBEXEC - I think I understand them but want to investigate further.
3) I think the definition of variables in HUBRAM and how they are used is going to take some documenting. More will follow on this as I play more.
4) Global labels. You'll notice that I have a "me" and a "Me2" because the labels are global to the program. Current local labels ":me" only have scope between global labels. Some sort of "section local" label would be nice.
This program:
It basically just tries to show all the varios ways you can use COGINIT to fire off new COGs with COGINIT loading COGs and running in COGEXEC, the COG starting in HUBEXEC and loading itself, the DEBUG vectors and such. Hopefully the examples will get anyone going if they are stuck or trigger some inspiration on things I didn't try. The cog0-cog7 labels aren't used in the program but help the narrative. All the COGINITs are using named COGS instead of "next available" just so we have control.
The program starts in HUBEXEC at HUBRAM $0 running in COG0. The first thing it does is replace the IRET0 in the debug vectors for COG3 so it points to a debug routine, we'll use this later.
Once COG0 is done with all the steps below, it kills itself
COG1: just a standard COGINIT of COG1. The COGINIT loads $1F0 (or $1F8) longs from HUBRAM starting at the target address. COG1 starts running at the target address. Nothing unexpected here. This COG image happens to be above the $1000 HUBRAM address.
COG2: Another standard COGINIT of COG2. The COG image in this case is below the $1000 HUBRAM address - in this case, it is under the $1FF HUBRAM space and would actually work as "COGINIT $2,#@cogwait" without the LOC.
COG3: COGINIT of COG3 - the DEBUG vector has been reset to point to my debug routine hblink instead of being the default IRET0. This debug ends up running in HUBEXEC even though you did not specify HUBEXEC on the COGINIT. Not unexpected base on addresses involved. I believe you need to pay attention to D and S registers here - your debug code will see the COGRAM of the running COG for any D and S references. This isn't a surprise either but does cause concerns with anything you expect to be initialized because you initialized it in your programs variable space.
COG4: COGINIT to some HUBEXEC code to load and initialize COGRAM. When done, you just JMP to the entry point of your COG code. This is kind of cool in that you can have all your initialization code in HUBRAM and not use any precious COGRAM for initialization code. I didn't find any surprises or unexpected side effects here. The obvious follow on here is to recover the HUBRAM space this image sat in for buffer space or another COG image. This ability to start in HUBEXEC, load your own COGRAM and then switch to COGEXEC has a lot of potential. Cool beans!!
COG5: The same thing we did with COG2 except we set the HUBEXEC bit. This has different results depending on where your COG image is defined. If it is below $1FF, then any variables you have defined do NOT have the defined values. In this example, the COG does NOT wait with the LED on like the same code does with COG2, it goes directly to the COGINIT of the blink routine. This code appears to be location dependent and something you need to be aware of. Pre-initialized variables in HUBEXEC mode have not given me consistent results depending on where they end up in the memory space. I'm still not sure I can predict the outcome until I try it.
COG6: This start out like the COG2 example except in a few lines, the COG0 HUBEXEC code goes out to change the debug vector. Kind of cool to effect other COGs from code running in another COG. Bunches of potential in this feature as well as now having interrupts.
COG7: nothing exciting, just another blinking COG. I was using it during testing to make sure I didn't break things.
I think that is everything of note in this program. There is a lot more COGINIT stuff to play with, I'm sure. If I missed something, let me know. If you dispute anything or want to correct any of my bad assumptions or conclusions, PLEASE let em know. If I need to clarify things, well, just ask.
If you have something you want me to try and are too lazy/busy or don't have a FPGA yet, let me know.
Here's the code if you don't want to download and print to follow this:
dat orgh 0 loc ptra,#@jmp_hblink ' set COG3 DEBUG vector prior to rdlong vector,ptra ' COGINIT wrlong vector,##DEBUGV_3 cog1 loc adra, #@blink coginit #1, adra ' boring old COGINIT - COGINIT does load ' of COGRAM starting at blink for $1F0 longs cog2 loc adra, #@cogwait coginit #2, adra ' another COGINIT - just to see that you can ' gather COG images under multiple 'org 0' ' this one will COGINIT inside itself cog3 loc adra, #@blink coginit #3, adra ' COGINIT IRET vector is set to jmp #@hblink cog4 coginit #$24,#@cog_prestart ' start COG in HUBEXEC, load it yourself ' jump to COGEXEC after load and any init cog5 loc adra,#@cogwait coginit #$25, adra ' like start of COG2 above but starts in ' HUBEXEC - this was acting differntly ' before I moved the COG image orgs after ' 'org $1000 - needs more investigation cog6 loc adra,#@cogwait coginit #6, adra ' this COG gets it's DEBUG vector changed ' by the COG0 HUBEXEC code after COGINIT cog7 loc adra, #@blink coginit #7, adra ' run a high cog to get different blink rate mov delay,#1 shl delay,#28 waitx delay ' let COG6 wait a bit before we reset loc ptra,#@jmp_hblink ' DEBUG vector and then re-COGINIT it rdlong vector,ptra wrlong vector,##DEBUGV_6 loc adra,#@blink coginit #6, adra ' force a stalled COG to go to "debug" ' kill COG0 cogid me cogstop me ' HUBEXEC code to load a COG's COGRAM with code before jumping to it. cog_prestart mov delay,#1 shl delay,#26 waitx delay loc ptra,#@cogwait ' grab the HUBRAM address of the image ' you built for this COG setq #$1F8 ' could load just the actual size rdlong 0,ptra ' at this point, you could do any intialiazation of COGRAM ' required while still in HUBEXEC mode - this allows you ' to remove intialiation code from precious COG space if needed jmp #0 ' this could be any COGRAM entry point ' you choose - it depends on how you build ' your COG image under the org ' some HUBRAM variable space ' This gets interesting and probabaly needs some experimenting ' and some examples and use cases documented ' me long 0 delay long 50_000_000 vector long 0 org 0 ' Build a COG image here cogwait cogid me2 setb dirb,me2 setb outb,me2 shl ticks, me2 waitx ticks notb outb,me2 loc adra,#@blink coginit me2,adra ' restart myself with a new COG image ticks long 50_000_000 ' this value gets loaded into COGRAM ' so the value is only initialized when ' you start this code in COGEXEC ' for HUBEXEC, this variable ' needs to be intialized as long as it ' is defined before $1F0 - if you move ' COG org 0 AFTER "orgh $1000" it does ' not need to be intialized - puzzling me2 res 1 ' needed to call this me2 since labels ' are global - local labels only have ' scope between global labels ' Build *MORE* of my HUB image here orgh $1000 jmp_hblink jmp #@hblink ' insruction to load DEBUG vector with ' this is code that will run as HUBEXEC - my "debug" routine hblink cogid me add me,#8 mov delay,#1 ' you actually need to initialize shl delay,#23 ' delay since it really exists in ' COGRAM when you refer to it in ' an S or D field - the initialized ' value is in HUBRAM if you want it setb dirb,me hblink1 notb outb,me waitx delay jmp @hblink1 '***************************** '***** COG IMAGE FOLLOWS ***** '***************************** org 0 ' build a COG image here blink cogid x setb dirb,x notb outb,x add x,#16 shl x,#18 waitx x jmp @blink x long 0 con ' addresses for debug Interrupt vectors DEBUGV_0 = $FFFC0 ' COG0 DEBUGV_1 = $FFFC4 ' COG1 DEBUGV_2 = $FFFC8 ' COG2 DEBUGV_3 = $FFFCC ' COG3 DEBUGV_4 = $FFFD0 ' COG4 DEBUGV_5 = $FFFD4 ' COG5 DEBUGV_6 = $FFFD8 ' COG6 DEBUGV_7 = $FFFDC ' COG7 DEBUGV_8 = $FFFE0 ' COG8 DEBUGV_9 = $FFFE4 ' COG9 DEBUGV_A = $FFFE8 ' COGA DEBUGV_B = $FFFEC ' COGB DEBUGV_C = $FFFF0 ' COGC DEBUGV_D = $FFFF4 ' COGD DEBUGV_E = $FFFE8 ' COGE DEBUGV_F = $FFFEC ' COGF
General notes:
1) I was able to use "COGINIT #cog,#@target" UNTIL I moved the COGRAM sections (org 0) past the "orgh $1000", once I did this, I needed to use LOC and COGINIT as in the code above. When moved higher in hubram, you get the "exceeds 511" message. I understand this and understand why you need the LOC & COGINIT. It isn't a problem since usually your target will be in a higher address range - just use LOC & COGINIT all the time
2) There are also some variable initialization issues when running in HUBEXEC - I think I understand them but want to investigate further.
3) I think the definition of variables in HUBRAM and how they are used is going to take some documenting. More will follow on this as I play more.
4) Global labels. You'll notice that I have a "me" and a "Me2" because the labels are global to the program. Current local labels ":me" only have scope between global labels. Some sort of "section local" label would be nice.
This program:
It basically just tries to show all the varios ways you can use COGINIT to fire off new COGs with COGINIT loading COGs and running in COGEXEC, the COG starting in HUBEXEC and loading itself, the DEBUG vectors and such. Hopefully the examples will get anyone going if they are stuck or trigger some inspiration on things I didn't try. The cog0-cog7 labels aren't used in the program but help the narrative. All the COGINITs are using named COGS instead of "next available" just so we have control.
The program starts in HUBEXEC at HUBRAM $0 running in COG0. The first thing it does is replace the IRET0 in the debug vectors for COG3 so it points to a debug routine, we'll use this later.
Once COG0 is done with all the steps below, it kills itself
COG1: just a standard COGINIT of COG1. The COGINIT loads $1F0 (or $1F8) longs from HUBRAM starting at the target address. COG1 starts running at the target address. Nothing unexpected here. This COG image happens to be above the $1000 HUBRAM address.
COG2: Another standard COGINIT of COG2. The COG image in this case is below the $1000 HUBRAM address - in this case, it is under the $1FF HUBRAM space and would actually work as "COGINIT $2,#@cogwait" without the LOC.
COG3: COGINIT of COG3 - the DEBUG vector has been reset to point to my debug routine hblink instead of being the default IRET0. This debug ends up running in HUBEXEC even though you did not specify HUBEXEC on the COGINIT. Not unexpected base on addresses involved. I believe you need to pay attention to D and S registers here - your debug code will see the COGRAM of the running COG for any D and S references. This isn't a surprise either but does cause concerns with anything you expect to be initialized because you initialized it in your programs variable space.
COG4: COGINIT to some HUBEXEC code to load and initialize COGRAM. When done, you just JMP to the entry point of your COG code. This is kind of cool in that you can have all your initialization code in HUBRAM and not use any precious COGRAM for initialization code. I didn't find any surprises or unexpected side effects here. The obvious follow on here is to recover the HUBRAM space this image sat in for buffer space or another COG image. This ability to start in HUBEXEC, load your own COGRAM and then switch to COGEXEC has a lot of potential. Cool beans!!
COG5: The same thing we did with COG2 except we set the HUBEXEC bit. This has different results depending on where your COG image is defined. If it is below $1FF, then any variables you have defined do NOT have the defined values. In this example, the COG does NOT wait with the LED on like the same code does with COG2, it goes directly to the COGINIT of the blink routine. This code appears to be location dependent and something you need to be aware of. Pre-initialized variables in HUBEXEC mode have not given me consistent results depending on where they end up in the memory space. I'm still not sure I can predict the outcome until I try it.
COG6: This start out like the COG2 example except in a few lines, the COG0 HUBEXEC code goes out to change the debug vector. Kind of cool to effect other COGs from code running in another COG. Bunches of potential in this feature as well as now having interrupts.
COG7: nothing exciting, just another blinking COG. I was using it during testing to make sure I didn't break things.
I think that is everything of note in this program. There is a lot more COGINIT stuff to play with, I'm sure. If I missed something, let me know. If you dispute anything or want to correct any of my bad assumptions or conclusions, PLEASE let em know. If I need to clarify things, well, just ask.
If you have something you want me to try and are too lazy/busy or don't have a FPGA yet, let me know.