Shop OBEX P1 Docs P2 Docs Learn Events
Wrlong, use ram defined in spin in assembly — Parallax Forums

Wrlong, use ram defined in spin in assembly

TransistorToasterTransistorToaster Posts: 149
edited 2007-06-13 23:15 in Propeller 1
Hello,
I am trying to use WRLONG in assembly to write to main memory. My code below is supposed to copy from a register (I put INA for figuring out how to do this) into main RAM.

VAR
bufferInMainRam[noparse][[/noparse]256]
PUB
cogstart(@asmStart,0)
DAT
org
mov pMainRam, #bufferInMainRam
movs :transferToMainRamLoop, pMainRam
:transferToMainRamLoop wrword ina,0

res pMainRam 4


I could not figure out how to specify a block of ram already defined in SPIN to the assembly section of the code. The compiler would flag an error at "mov pMainRam, #bufferInMainRam". What is the correct way?

This is a stupid question, but I have to be sure: Is it correct to say that the "res pMainRam 4" command allocated the ram in cog ram space?

Comments

  • Jasper_MJasper_M Posts: 222
    edited 2007-03-20 19:04
    The correct way is to pass the asm Cog the address is by putting it in PAR register.

    LONG myBuffer[noparse][[/noparse]256]

    ...

    cognew(@asmCode, @myBuffer)

    ...
    'ASM CODE:
    asmCode rdlong cogRamVar, par
    ...
    cogRamVar res 1

    The idea is that the second argument of cognew (and the third parameter of coginit) appears in the read-only par register. So you can pass one pointer or value to your asm code using that.


    Also, there is no cogstart function, only coginit and cognew. The res has also to be AFTER the label. And if you're reserving a long, use "res 1", not "res 4", the number is number of longs, not number of bytes here. Also, RES directives must be the last thing in your asm code - they can't be followed by asm code or long/word/bytes.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-03-20 19:48
    Try it using something besides INA, I can't precisely remember, but I think INA cant be used with WR(LONG/WORD/BYTE) because it is accessing in the destination location of the assembly instruction which causes it to access the shadow register and not the real INA you are expecting. First use MOV INA to a variable then use WRWORD.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • Jasper_MJasper_M Posts: 222
    edited 2007-03-20 19:56
    Paul Baker (Parallax) said...
    Try it using something besides INA, I can't precisely remember, but I think INA cant be used with WR(LONG/WORD/BYTE) because it is accessing in the destination location of the assembly instruction which causes it to access the shadow register and not the real INA you are expecting. First use MOV INA to a variable then use WRWORD.

    Yes, I remember debugging at least one hour a problem like that. INA can't be a destination register. eg. "test ina, #1 wz" won't work, a temporary copy has to be made... Paul, are INA registers the only ones that are like this? Can FRQA, CNT etc. be used as destination?
  • rokickirokicki Posts: 1,000
    edited 2007-03-20 20:15
    This has wasted so much time for so many people. Could we please modify the assembler to either
    not permit this, or complain about it? Yes, existing code will need to be modified, but my claim is
    that code needs to be modified anyway; if you really want to use a shadow register you should be
    forced to declare that explicitly (using ina_shadow or some such). This is such a common trap.
  • TransistorToasterTransistorToaster Posts: 149
    edited 2007-03-20 20:52
    Thanks for your response. It's almost working now. I seem to have only one long arriving at my destination. Do you see why? In the below code, I was a bit scared for alignment so I bumped the pointer a bit forward.
    VAR
      byte samples[noparse][[/noparse]256]    
    PUB
       cognew(@asmStart,@samples)    'Start assembly
    DAT
         org 0                   'assembly sourcedest1 , source2
    asmStart
    
    transferToMainMemV1
            mov    pMainRam, par
            add    pMainRam, #4
            mov    samplesCounter, #62 
            nop
    :transferToMainMemLoopV1
            wrlong samplesCounter, pMainRam
            add    pMainRam, #4
            djnz   samplesCounter,:transferToMainMemLoopV1 '4cc if jump is required, 8cc if no jump 
            jmp    asmStart 'Loop indefinately
            
    pMainRam       RES 1
    samplesCounter RES 1
    
    
  • TransistorToasterTransistorToaster Posts: 149
    edited 2007-03-20 20:56
    Thanks for the heads up on INA.
  • Jasper_MJasper_M Posts: 222
    edited 2007-03-20 21:55
    transistortoaster said...
    Thanks for your response. It's almost working now. I seem to have only one long arriving at my destination. Do you see why? In the below code, I was a bit scared for alignment so I bumped the pointer a bit forward.
    VAR
      byte samples[noparse][[/noparse]256]    
    PUB
       cognew(@asmStart,@samples)    'Start assembly
    DAT
         org 0                   'assembly sourcedest1 , source2
    asmStart
    
    transferToMainMemV1
            mov    pMainRam, par
            add    pMainRam, #4
            mov    samplesCounter, #62 
            nop
    :transferToMainMemLoopV1
            wrlong samplesCounter, pMainRam
            add    pMainRam, #4
            djnz   samplesCounter,:transferToMainMemLoopV1 '4cc if jump is required, 8cc if no jump 
            jmp    asmStart 'Loop indefinately
            
    pMainRam       RES 1
    samplesCounter RES 1
    
    


    The obvious problems here are:

    1. djnz samplesCounter,:transferToMainMemLoopV1
    should be
    djnz samplesCounter,#:transferToMainMemLoopV1
    Otherwise it jumps to the memory address stored in :transferToMainMemLoopV1, and would be equivalent to djnz samplesCounter, #pMainRam, which is obviously a bug.

    2. jmp asmStart
    same bug, should be jmp #asmStart

    3. Adding a number won't help with the alignment - the end result is still not divisible by 4. Instead, I'd suggest declaring samples as

    long samples[noparse][[/noparse]64]

    This makes it long aligned. If you'd want to access it as bytes in Spin (it's no problem in asm, in ASM it doesn't matter if it's declared long or byte or whatever), use samples.BYTE[noparse][[/noparse]index] instead of samples[noparse][[/noparse]index].

    4.The nop is unnecessary. It is needed only with self-modifying code, where movd or movs instructions or something similar are involved, like

    movd readData, #register

    readData mov r1, 0

    won't work, but

    movd readData, #register
    nop
    readData mov r1, 0

    will work.

    5. I'm not exactly sure what you're trying to do - currently you are writing longs into the array that contain numerical values from 62 to 1.
    EDIT: If you're trying to move stuff from Cog memory to Hub memory, you have to use self-modifying code. The wrbyte/word/long instructions write the value of the destination into Hub memory, destination is not a pointer there.

    Post Edited (Jasper_M) : 3/20/2007 10:01:26 PM GMT
  • Jeff MartinJeff Martin Posts: 751
    edited 2007-03-20 22:16
    rokicki said...
    This has wasted so much time for so many people. Could we please modify the assembler to either
    not permit this, or complain about it? Yes, existing code will need to be modified, but my claim is
    that code needs to be modified anyway; if you really want to use a shadow register you should be
    forced to declare that explicitly (using ina_shadow or some such). This is such a common trap.
    There are actually times when this feature becomes very handy, like resetting the phsx register to some offset of the last-written value (mov phsa, #offset).·

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Jeff Martin

    · Sr. Software Engineer
    · Parallax, Inc.
  • rokickirokicki Posts: 1,000
    edited 2007-03-20 22:42
    Absolutely; I am in no way criticizing its utility as I have used it myself in the past.
    Nonetheless, when it is intended it should be clearly written as such. For every
    person who trips over this and posts it on the forum, there are probably a hundred
    who trip over it and just figure one of:

    1. The propeller is broken.

    2. I can't get this stupid program to work; I am so stupid.

    I mean, do we want to be an elite priesthood where you need to pay your dues
    (trip over these issues and study enough until you understand them) before you
    can even write a simple assembly language program? Or do we simply want our
    programming language to be explicit in these issues, and require you to acknowledge
    the different semantics of these shadow registers if and only if you use them?

    Letting a neophyte "access" shadow registers using the name of the "normal"
    registers, when he or she probably does not know of (nor wants to know of)
    the shadow registers at all in this point, is doing them, and all of the rest of us,
    a grave disservice.

    Accessibility is Parallax's stock in trade. Let's not give it up here guys.
  • Jasper_MJasper_M Posts: 222
    edited 2007-03-20 22:52
    Umm... I have to agree with Rokicki, besides there is not a single good reason for using INA as dst AFAIK. ... And I actually did check the propeller inputs with a multimeter : P ... just to see that the voltages don't match with (what I thought were) INA contents : / ...
  • JamesxJamesx Posts: 132
    edited 2007-03-20 23:37
    Umm... I also would agree with Rokicki. It would be nice if the Propeller Tool caught common, simple mistakes. As another example, another common mistake is not putting a "#" in front of a label. Seems like that would be easy for the Tool to catch, and comment on.

    To the question: "I mean, do we want to be an elite priesthood where you need to pay your dues (trip over these issues and study enough until you understand them) before you can even write a simple assembly language program?"
    I would say "Make it easier". There is so much to learn, and mistakes are so easy to make, it would be nice for the Tool to assist and guide.

    Jim C
  • rokickirokicki Posts: 1,000
    edited 2007-03-20 23:55
    I like this (the # thing). So jmp (and call) would require the #, and if you wanted an indirect jmp, no big deal,
    you just use jmpr (or something similar) with an unadorned label (or whatever other operand you want). We
    already have call and ret which are just variants of jmp, so it's not like we're totally minimally orthogonal
    anyway.

    It's just like in Java. There's no difference between overriding a method and declaring a brand new method.
    So if you make the tiniest error (order of arguments, type of arguments) when you intend one, you get the
    other, and the compiler helps you not at all, and you spend the day debugging. C# got that one right.
  • KaioKaio Posts: 253
    edited 2007-03-21 14:30
    Hi transistortoaster,

    you can use POD to debug your assembly program. Currently you cannot show main memory but I have it on the list for the next release.

    If need assistance to prepare your file for debugging I can help you.
  • TransistorToasterTransistorToaster Posts: 149
    edited 2007-03-21 15:04
    kaio,
    I'll check out the POD.

    Jasper, rokiki
    >I like this (the # thing). So jmp (and call) would require the #
    It was a discovery for me to learn that here, the jump is absolute(with #) or indexed (without #). In general, most assembly languages have a different jump instruction identifier for an indexed jump so that's why I never bothered with the #.

    >3. Adding a number won't help with the alignment -
    That was to safeguard against writing on data before the array of bytes.

    >5. I'm not exactly sure what you're trying to do - currently you are writing longs into the array that contain
    >numerical values from 62 to 1.
    >EDIT: If you're trying to move stuff from Cog memory to Hub memory, you have to use self-modifying code.
    >The wrbyte/word/long instructions write the value of the destination into Hub memory, destination is not a pointer there.
    You probably caught on that this was a baby step to understand how come my code was not working. It was erroneous in the branching, which I didn't know at that time. After learning the mistake I successfully implemented the self modifying code to work for the cogram to mainram copy.
  • Jasper_MJasper_M Posts: 222
    edited 2007-03-21 15:13
    Ah, good to hear you got it working ^___^
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-21 15:38
    Like in PBasic, there should be a compiler directive statement and one of the options would be to suppress specific kinds of warning messages (like for the conditions mentioned in this thread). The warnings would be enabled by default. This kind of object by object control is needed since a beginning programmer might reference a library object that needs to use these shadow registers (or anything else similar) and shouldn't have to figure out the warning messages from the library object.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-03-21 16:14
    The issue is there is no warnings with the compiler, it's either an error or not an·error and to change it would be a major undertaking. Chip is deeply in designing the new chip, to have him mess with the compiler at this point would delay everything.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • JamesxJamesx Posts: 132
    edited 2007-03-22 00:04
    No doubt there are dozens of important projects on y'all's plates. Perhaps the concept of adding a few warnings to the compiler could go on a list somewhere as a maybe project. For some rainy day when there's nothing else to do...

    Jim C
  • janbjanb Posts: 74
    edited 2007-06-13 19:21
    Hi TransistorToaster,
    would you mind to post the final working code? I'm reading now different discussions trying to learn assembler.
    This was is very instructive
    Thanks
    Jan
  • TransistorToasterTransistorToaster Posts: 149
    edited 2007-06-13 23:15
    Jan,
    Here you go:

    VAR
      long mainRamArray[noparse][[/noparse]256]    'variable space in main ram
    PUB
       cognew(@asmStart,@mainRamArray)    'Start assembly
    
    
    DAT
         org 0                 
    '1 FILL THE cogRamArray WITH USEFUL DATA
    
    '2 TRANSFER THE RAM
    TransToMainMemV3
           mov   pMainRam, par                        
           mov   pCogRam, #CogRamArray                 
           mov   indexCounter, #64  
           movd  :acquireTransToMainMemLoopV3 ,pCogRam   ' MODIFIES THE LINE OF CODE
           nop                                    
    :TransToMainMemLoopV3   wrlong   CogRamArray, pMainRam  'THIS CODE WILL GET CHANGED 
           add    pMainRam, #4                                      
           add    pCogRam, #1                                      
           movd   :TransToMainMemLoopV3 ,pCogRam      '  MODIFIES THE LINE OF CODE
           djnz  indexCounter, #:TransToMainMemLoopV3       
    
    
    CogRamArray   RES 64  '64 longs=256 bytes  
    pCogRam         RES 1
    pMainRam        RES 1
    indexCounter    RES 1
    
    
Sign In or Register to comment.