Shop OBEX P1 Docs P2 Docs Learn Events
ASM reading PAR value and writing to hub - advice needed — Parallax Forums

ASM reading PAR value and writing to hub - advice needed

CynicCynic Posts: 8
edited 2009-06-02 18:47 in Propeller 1
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
·····················

Comments

  • jazzedjazzed Posts: 11,803
    edited 2009-05-30 20:53
    Make outVal a long ... VAR data can go *anywhere* and a byte variable can easily be put on a non-long aligned address. I don't see any other problems.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • localrogerlocalroger Posts: 3,452
    edited 2009-05-30 21:02
    OutVal needs to be a long, as jazzed said. Par is only 14 bits; it assumes a long-aligned target in Hub RAM, and the lower two bits are always 0.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-05-30 21:30
    outVal will be on a long boundary (being the only non-long in the VAR section), so no worries there. The stack may be a bit small, though. I'd increase it to 32, just for good measure. Try changing your waitcnt delay a little. outVal may well be cycling through all those values, and you're just catching it when it's a "B". That'd be a weird coincidence, but it's possible.

    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! smile.gif

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2009-05-30 22:29
    Learn something new every day I guess. Ya, 9 is a little tight for a stack. Wonder if your code works with the display function in the main cog.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • CynicCynic Posts: 8
    edited 2009-05-31 21:57
    Thank you all for the advice. I still haven't got the problem sorted out yet - but am working on it. Changing the byte to a long does not make a difference. Undoubtedly the issue is something simple.

    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
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-05-31 22:10
    Cognew is the problem when you try to start the display-routine. Remove the brackets around the function name and it works.

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-05-31 22:13
    Wow, MagIO2: good eye!

    -Phil
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-05-31 22:25
    We have a saying here in germany: Even a blind chicken sometimes finds a corn. ;o)
  • CynicCynic Posts: 8
    edited 2009-06-01 18:49
    It now works!!! Thank you very much.

    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.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-01 20:20
    Do you mean that cynically? ;o)
  • jazzedjazzed Posts: 11,803
    edited 2009-06-01 20:52
    I'm confused. Where is it documented that enclosing the spin cognew method in parens causes the return code to be used instead of the method?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-01 21:14
    It's by the nature of SPIN compiler (and other compilers as well). Everything in brackets (except the parameters in a function call of course) is treated like an expression which has to be solved. Solving a function means to call it and take the return value as result.

    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.
  • BradCBradC Posts: 2,601
    edited 2009-06-01 23:31
    MagIO2 said...
    It's by the nature of SPIN compiler (and other compilers as well). Everything in brackets (except the parameters in a function call of course) is treated like an expression which has to be solved. Solving a function means to call it and take the return value as result.

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-06-02 03:07
    This is definitely a subtle (but nonetheless unambiguous) trap for beginners. I've puzzled over how I might have expressed it differently and, frankly, nothing more elegant than a rather crude spincognew vs. asmcognew comes to mind. For elegance, it pales next to the current syntax. I'm sure that Chip gave this a lot of thought and didn't smply toss it off as obvious.

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2009-06-02 03:11
    My beginning knee-jerk reaction years ago was to use "@method" ... Oh well.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-06-02 03:35
    I suppose if Spin permitted method pointers that might be a candidate syntax. But things get really weird when parameters are involved, since a cognew can actually call the method it's starting and pass arguments to it, rather than just pointing to it. That's what makes me believe that this is something Chip struggled with a bit before settling on the current way of expressing things. As I said, it's certainly unambiguous — just very subtle.

    -Phil
  • mparkmpark Posts: 1,305
    edited 2009-06-02 04:05
    I think the current syntax is a mistake. It's crazy that
    cognew( blah(3), 0 )
    and
    cognew( 0+blah(3), 0 )
    do completely different things.
  • BradCBradC Posts: 2,601
    edited 2009-06-02 05:15
    mpark said...
    I think the current syntax is a mistake. It's crazy that
    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!
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-06-02 05:21
    mpark,

    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
  • mparkmpark Posts: 1,305
    edited 2009-06-02 07:28
    Brad,
    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!
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-06-02 15:52
    Part of the "problem" is that the syntax has to hide so much stuff that happens in the background when a Spin cog is started. At its lowest level a cognew for a Spin cog is no different from one for an assembly cog. But there's more prep work involved. First, a control block has to be set up that points to the method and to the assigned stack. Then the method's arguments have to be pushed onto the stack. Finally a cognew that points to the interpreter and to the control block gets executed. (At least that's what I infer must be happening.)

    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
  • BradCBradC Posts: 2,601
    edited 2009-06-02 16:09
    Phil Pilgrim (PhiPi) said...


    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)).

    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!
  • jazzedjazzed Posts: 11,803
    edited 2009-06-02 18:47
    I've always interpreted the @ in spin as meaning "address of." Don't see how this would be pollution form a user perspective, but do understand how it complicates the compiler a little. The compiler only has to get the algorithm right once though [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
Sign In or Register to comment.