Shop OBEX P1 Docs P2 Docs Learn Events
A little memory access trouble with assembler — Parallax Forums

A little memory access trouble with assembler

NefastorNefastor Posts: 14
edited 2007-04-24 18:22 in Propeller 1
Hi guys,

I'm having a little frustration about accessing the main RAM from a cog.

Fixing this would be a lot easier if I had some kind of debugger, but we ain't there yet.

Basically, here's what I want to do :

- As cog 0 starts running spin, it declares an array variable such as :

long ARRAY[noparse][[/noparse]30]

- In the code, cog 0 launches code on cog 1 that will read and write into ARRAY[noparse]/noparse, therefore cog 1 is started with the address of the array as its parameter.

I'm a C guy, so initially I thought ARRAY would be the pointer to array ARRAY[noparse]/noparse. When the code didn't work, I tried passing @ARRAY and also @ARRAY[noparse][[/noparse]0], but nothing changed. Or at least that's what it looks like since I don't have a debugger to check what's really happening.

I would like to know exactly what happens when I declare an array of longs in Spin : my assumption is that the array starts at element 0 and the next elements are located at contiguous addresses (+4, +8, +12...). Can you confirm that ?

Also, can you confirm which expressions return the array's start address ? (ARRAY, @ARRAY, @ARRAY[noparse][[/noparse]0]...) ? Is there a page in the manual that I should read more carefully ?

- In cog 1, the software is in assembler, so the address I'm passing it ends up in cog 1's PAR register. I'm using a very conservative approach to transfering the data : I initialize a register with the value of PAR and add 4 to it to access the next element of the array, and I use that register as the address register in wrlong and rdlong. I'm not even trying self-modifying code for now.

I think the problem most likely comes from my assembler code and the way I declare my registers :

After the last instruction, I do this :

LABEL long $initial_value

repeatedly. I have found this to work just fine : in any instruction I can use the LABEL to specify my register and I haven't noticed any odd behaviour.
However I'm not too sure about how to get the ADDRESS of the register. Again, as far as I can tell, I can simply use #LABEL.

But all examples of code I've read on the forum use ":LABEL" instead of "LABEL". I think I have misunderstood the purpose of the colon before a label : where is it explained in the manual ?

Right now I use a colon before a label if it's a label to which I intend to jump, and I don't use one when I want the label to represent a register, but from what code I see on the forum this doesn't seem to matter.

As you can see I'm a bit lost with this stuff. Help me please cry.gif

Jean

Comments

  • NefastorNefastor Posts: 14
    edited 2007-01-14 14:28
    Ah, I forgot another question :

    If I do something like this in assembler :

    REG1 long 0
    REG2 long 0
    REG3 long 0
    ...

    Can I always be 100% sure that REG1, REG2... will be located in cog RAM at contiguous memory locations so I can safely access them using pointers ?

    Thanks

    Jean
  • Mike GreenMike Green Posts: 23,101
    edited 2007-01-14 16:38
    1) Let's say you have an array X declared in Spin as "long X[noparse][[/noparse]20]" and you start an assembly routine Y with "COGNEW(@Y,@X)". This starts a new cog with the assembly code beginning at Y and the PAR register will have the address of the first long in X in it. To an assembly routine, the main memory (Hub) locations look somewhat like I/O and you have to use the RDxxxx and WRxxxx instructions to access them. You also have to do your own indexing (with a granularity of 4 ... 4 bytes per long). To read the i-th long in the array into a Cog memory location Z, you'd do:
              mov   temp,Z     ' get the index
              shl     temp,#2  ' multiply by 4
              add    temp,PAR ' add the starting address
              rdlong Z,temp   ' read the value into Z from the array
    -or-    wrlong Z,temp  ' write the value from Z into the array
    
    


    2) What you declare in a single DAT section will be in the order you declare it. Nothing is moved.
  • NefastorNefastor Posts: 14
    edited 2007-01-14 17:18
    Thanks Mike :

    I wrote my code using the rules you just described (not surprising, of course). But it doesn't work, so I'll have to keep looking for the problem. I've narrowed it down to a sequence of 15 instruction that does a sequential read from main memory followed by a sequential write, between a lockset / lockclr pair.

    Can you confirm that when I write :

    mov A,#B

    Where A and B are two registers, I actually place the address of B into A ? That's the most likely cause for my problem (i.e. I assume I get a pointer when in fact I get a value or garbage).

    Damn it would REALLY help to have a nice debugger... if I had time I'd port gbd, it shouldn't be too hard to write a stub since :
    a/ there's no stack pointer to worry about
    b/ you can easily control the Z and C flags
    c/ it's easy to modify the code in memory to set breakpoints.

    The tough problem would be debugging across multiple cogs.

    I'm on a tight time constraint right now, but if I ever have time I'll definitely do something.

    Anyway, can you tell me if the colon in labels has any specific meaning at all ?

    Thanks,

    Jean
  • Tracy AllenTracy Allen Posts: 6,660
    edited 2007-01-14 17:45
    In,
    mov A,#B
    if B happens to be register 17, then A will contain 17, not the contents of register 17.

    labels with a : in front are local. Their scope lies only between two global labels. That way you can reuse names like :loop for dumb little local loops in several different contexts.
    zing
    :loop
      djnz N, #:loop  ' note the #:
    zang
    :loop
      djnz M,#:loop
    zoom
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Mike GreenMike Green Posts: 23,101
    edited 2007-01-14 17:51
    To rephrase Tracy's comments, "mov A,#B" copies the value B into register A. If B is an address, it will copy the address into register A.
  • NefastorNefastor Posts: 14
    edited 2007-01-14 19:43
    I think I understand what Tracy says, if "register 17" means the long at address 17 in cog RAM. However Mike I'm not sure I understand your post : what do you mean when you say "if B is an address" ?

    Do you mean a label ? (label == symbol for an address)

    Jean
  • Mike GreenMike Green Posts: 23,101
    edited 2007-01-14 21:01
    Jean,
    I used the word address because it might indeed be a label which might be a symbol for an address. On the other hand, it might be an expression of some kind which is evaluated by the compiler (and might not really be an address). Sorry if I added to the confusion.
  • NefastorNefastor Posts: 14
    edited 2007-01-14 22:49
    Mike Green said...
    Jean,
    I used the word address because it might indeed be a label which might be a symbol for an address. On the other hand, it might be an expression of some kind which is evaluated by the compiler (and might not really be an address). Sorry if I added to the confusion.

    No harm done, after all we can always come back to the forum and sort it all out wink.gif

    Besides, you've confirmed what I was thinking originally. I still haven't found the cause of my problem, but when I do (and assuming it's interesting) I think I'll post in the "traps and tricks" thread.

    Ultimately, I want to write code for circular FIFO's that would allow flexible and simple communication between cogs. It'd be nice to have some sort of mechanism for this kind of peer-to-peer transfers, though I can see how that would be tough to implement in hardware (I've worked on multi-core processors at TI)

    Jean
  • Mike GreenMike Green Posts: 23,101
    edited 2007-01-14 23:02
    Look at the code for the keyboard driver that's included with the Propeller Tool. It implements a circular FIFO.
  • bambinobambino Posts: 789
    edited 2007-01-15 18:01
    Thanks Mike,

    That is the problem I'm up against now: Buffers + multiple cogs.
  • rjo_rjo_ Posts: 1,825
    edited 2007-04-24 16:53
    Mike,

    I know that I'm probably not going to be asking this question correctly, but you seem to have strange powers of divination... This is another way of thinking generally about the question that started this thread. So. I'm going to give it a shot... and if I am wrong... this would be a good time to find out[noparse]:)[/noparse]

    Would it be reasonably correct to say that for any "symbolic label" identified as a variable... a particular assembly instructions might accept that label and operate on it as a "register(memory location) address" associated with that label... while another assembly instruction might operate on the actual contents stored at the memory address associated with that same label? So, what a particular label usage "means" is defined by the context of the instruction?

    In other languages... there is a clear syntax for addresses vs. contents held at addresses... in Propeller assembly ... the syntax is defined by the operation?

    Thanks,

    Rich
  • Mike GreenMike Green Posts: 23,101
    edited 2007-04-24 17:31
    Well, yes and no.

    In assembly like for the Propeller (there are exceptions in some other assemblers), labels either represent explicit constant values (CON stuff) or addresses. That's it. The actual instructions use that address to fetch or store a value or use the address as a literal constant (#x). The jump instructions copy the source value into the program counter (a special internal register). That's why jumps usually use the literal constant form of their source operand. The instruction determines how the destination and source values are used. As a destination, it's always used as an address. As a source, the instruction determines whether it's used as an address to fetch a value or the value itself (#x).

    In C, there is not a clear syntax for addresses vs. contents held at addresses, particularly where type checking is not used and addresses are passed as parameters to subroutines. There's no way to tell what the parameter value represents. It's a major source of errors in C programs at run-time. That's why most compilers now require typing as a default setting, but C doesn't require it.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-04-24 17:33
    Perhaps this may help you guys, it is code that is at the heart of my digital storage scope. It shows two working examples of buffers, the first is filling up a local buffer (:storeloop block), then writing that buffer to main memory (:writeloop block). The :hptr block is the initalization block for the :storeloop block.

    A word of warning, the ":hptr········ mov······ :hptr, par····················· 'use this loc as ptr to hub mem" is a bit of trickery that can only be used in a "run once and die" routine, if you have a permanent cog running multiple aquisitions, you would need to have a seperate variable to use for the hub pointer.

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

    Parallax, Inc.

    Post Edited (Paul Baker (Parallax)) : 4/24/2007 5:41:18 PM GMT
  • rjo_rjo_ Posts: 1,825
    edited 2007-04-24 18:22
    You guys are great... and I'm not sucking up... that is a fact.

    Rich
Sign In or Register to comment.