ASM reading PAR value and writing to hub - advice needed
Cynic
Posts: 8
Hello All
I am trying to write a simple test program in which an ASM·cog updates a hub value and this hub value is then·read by spin code running in a different cog. I'm having a bit of trouble getting it working. I would really appreciate some advice as to why the code continuously outputs >B< rather than >(some value between A and P)< to the VGA display. I'm using the demo board.
Many thanks
CON
··
· _clkmode = xtal1 + pll16x···················· ' Crystal and PLL settings.
· _xinfreq = 5_000_000························· ' 5 MHz crystal.
OBJ
··
· VGA : "VGA_Text"
VAR
· long Stack[noparse][[/noparse]9]
· byte outVal
PUB start | val
· outVal :="B"
· ' start the display in a new cog
· cognew((DisplayVal),@Stack)
· ' this cog should now try to increment the outVal
· coginit(0, @entry, @outVal)
···
DAT
' the par should contain the hub address to write to
entry·················· mov···· t1,par··············· ' the outVal address
loop··················· rdbyte· t2,t1················ ' read the outVal value
······················· add···· t2,#1················ ' add 1 to it
······················· cmp···· t2,#$50 wc··········· ' is it greater than $50?
············· if_c····· jmp···· #write_it············ ' no it is not, just write
······················· mov···· t2,#$41·············· ' yes it is, put $41 in there
write_it··············· wrbyte· t2,t1················ ' write it back out
······················· jmp···· #loop················ ' do the next increment
·······················
t1 res 1
t2 res 1····················
·
PUB DisplayVal
··· VGA.start(16)
' this will display the content of the outVal, we should see it
' change as the assembly block writes to it···
· repeat
···· VGA.out(">")
···· VGA.out(outVal)
···· VGA.str(string("<",13))
···· waitcnt(clkfreq + cnt)····················· ' Wait 1 sec
·····················
I am trying to write a simple test program in which an ASM·cog updates a hub value and this hub value is then·read by spin code running in a different cog. I'm having a bit of trouble getting it working. I would really appreciate some advice as to why the code continuously outputs >B< rather than >(some value between A and P)< to the VGA display. I'm using the demo board.
Many thanks
CON
··
· _clkmode = xtal1 + pll16x···················· ' Crystal and PLL settings.
· _xinfreq = 5_000_000························· ' 5 MHz crystal.
OBJ
··
· VGA : "VGA_Text"
VAR
· long Stack[noparse][[/noparse]9]
· byte outVal
PUB start | val
· outVal :="B"
· ' start the display in a new cog
· cognew((DisplayVal),@Stack)
· ' this cog should now try to increment the outVal
· coginit(0, @entry, @outVal)
···
DAT
' the par should contain the hub address to write to
entry·················· mov···· t1,par··············· ' the outVal address
loop··················· rdbyte· t2,t1················ ' read the outVal value
······················· add···· t2,#1················ ' add 1 to it
······················· cmp···· t2,#$50 wc··········· ' is it greater than $50?
············· if_c····· jmp···· #write_it············ ' no it is not, just write
······················· mov···· t2,#$41·············· ' yes it is, put $41 in there
write_it··············· wrbyte· t2,t1················ ' write it back out
······················· jmp···· #loop················ ' do the next increment
·······················
t1 res 1
t2 res 1····················
·
PUB DisplayVal
··· VGA.start(16)
' this will display the content of the outVal, we should see it
' change as the assembly block writes to it···
· repeat
···· VGA.out(">")
···· VGA.out(outVal)
···· VGA.str(string("<",13))
···· waitcnt(clkfreq + cnt)····················· ' Wait 1 sec
·····················
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
BTW, you don't need the if_c jmp ...; just make the following statement depend on if_nc.
Also, since there's only the one hub variable, you can use par directly in your rdbyte and wrbyte, obviating any need for t1.
While you're at it, replace the coginit with a cognew. 'Might as well learn some good habits now!
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
Phil: you suggested replacing the coginit with a cognew - why would this be a better thing to do and hence a good habit? I do not understand the significance.
Thanks again
You have to understand what the SPIN code is compiled to. It calls the function and would use it's return value as parameter for cognew. But the function DisplayVal simply never returns.
-Phil
I am not sure why the brackets were around the DisplayVal call. I must have cut and pasted it in from some other code.
BTW, as Phil said the stack _was_ too small at 9. I had to also increase it to 32 before the code would work.
Thank you all for your assistance - it is much appreciated.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
Try it by using a function which returns the adress of a PASM-code and you will see that it works. As you see the cognew is in this case the version which runs PASM-code, that's because function names are magic in SPIN. You can't use these as function pointer as you can in C for example. Function-labels can only be used directly as function calls or in the cognew.
Actually, the reason the compiler does it this way is not so much the brackets deliberately cause it to be treated like an expression, but that the compiler looks at the first thing it comes across after the '(' and sees something other than a spin method, it then switches to generate code for th the PASM variant and evaluates whatever is there.
This also causes the common beginners trap where they do cognew(object.method(1,2,3),@stack). The compiler sees the object rather than the method call and generates a PASM coginit construct with the return value of the object.method call being used rather than calling the method itself.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"VOOM"?!? Mate, this bird wouldn't "voom" if you put four million volts through it! 'E's bleedin' demised!
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
-Phil
cognew( blah(3), 0 )
and
cognew( 0+blah(3), 0 )
do completely different things.
I'm not so sure about that particular example, but you must admit from the point of writing a compiler it makes it dead easy to determine which variant you are generating.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"VOOM"?!? Mate, this bird wouldn't "voom" if you put four million volts through it! 'E's bleedin' demised!
Yeah, well, I can't entirely disagree; but how would you fix it? I've puzzled over this conundrum numerous times and can't see an elegant way out that's consistent with the rest of the language. Who knows? Maybe brute force (i.e. spincognew and asmcognew) is called for. But yecch, it's just ugly.
-Phil
I also think it's crazy that
cognew( blah(3), 0 )
is OK but
cognew( blah(3)+0, 0 )
is illegal.
Phil,
"Consistent with the rest of the language" -- that's exactly the problem with cognew: you give it something that looks for all the world like a function call, only in this case it isn't. It's a use-mention distinction: outside of cognew, blah(3) calls the blah function; inside cognew, blah(3) just supplies the name and arguments of a function. It might as well be in quotation marks. And of course if it's a method in another object, it's back to a call.
Anyway, I don't mean to harp too much on Spin. It has its share of quirks and annoyances, but overall I enjoy coding in it. It's causing me many a sleepless night -- in a good way!
I'm beginning to think that Steve's idea (@method(args)) might have been best after all. This could be thought of as a pointer to a stub that calls method with args, so the syntax isn't that out of line. And it certainly eliminates the current subtle distinction between method(args) and (method(args)).
-Phil
I just see it as complicating things further. Instead of a slight confusion in the cognew/init function you now pollute the @ operator.
As long as you remember that the first thing the compiler sees in a cognew/init after the '(' *must* be the name of a method inside that object or else it will build an assembler cognew/init statement, you can't go wrong. This just needs to be drummed home some more and documented in big flashing lights.
All languages have their quirks that allow you to discharge a high caliber weapon into your own foot at close range. At least SPIN (somewhat like Pascal and other heavily typed languages) prevent you blowing your leg off in the process.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"VOOM"?!? Mate, this bird wouldn't "voom" if you put four million volts through it! 'E's bleedin' demised!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230