Shop OBEX P1 Docs P2 Docs Learn Events
C++ problem (was Question about DAT variables) — Parallax Forums

C++ problem (was Question about DAT variables)

David BetzDavid Betz Posts: 14,516
edited 2014-02-22 19:08 in Propeller 1
Should this code work? In particular, is this statement okay for referencing the "mailbox" variable in the DAT section? The value of that variable gets patched to the address of the mailbox before I load this code so it should have a valid address by the time this code runs.

This is the code I'm wondering about. Will it fetch the 32 bits that are pointed to by "mailbox" and assign it to "params"? The reason I'm asking is that I seem to be getting the wrong value in "params".
   repeat while (params := long[mailbox]) == 0

Here is the full code:
' This file was generated by spinwrap. Do not edit!

OBJ
  x : "test"

PUB dispatch | params, object, index, arg1, arg2, arg3, arg4
  repeat
    repeat while (params := long[@mailbox]) == 0
    longmove(@object, params, 6)
    case index
      0: result := x.set_pin({pin} arg1)
      1: result := x.set_pins({pin1} arg1, {pin2} arg2)
      2: result := x.swap_pins
      3: result := x.show_pins
      4: result := x.blink
      other: result := -1
    long[params] := result
    long[@mailbox] := 0

DAT
  mailbox long 0

Edit: Added @ in front of the mailbox references. That didn't fix the problem though.

Comments

  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 14:08
    I figured out at least part of my problem. What I didn't mention in my original post is that the "mailbox" variable in the DAT section contains the address of the mailbox. That means I need to do something like this instead of what I was doing before:
        repeat while (params := long[long[@mailbox]]) == 0
    
    Unfortunately, I'm still getting the wrong value in "index" so I have some more debugging to do.
  • Mike GMike G Posts: 2,702
    edited 2014-02-22 14:12
    What I didn't mention in my original post is that the "mailbox" variable in the DAT section contains the address of the mailbox.
    Try @@mailbox[index]
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-22 14:24
    As Mike points out, you need @@ -- the second @ provides the DAT offset for the current object.

    I'm working on a sign controller that holds patterns and their addresses in a table; here's a portion:
    MLP_11                long    %00000000_00011111
                            long    %00011111_00000000
    
                            word
    
      ML_Pats               word    @MLP_00, @MLP_01, @MLP_02, @MLP_03, @MLP_04, @MLP_05   
                            word    @MLP_06, @MLP_07, @MLP_08, @MLP_09, @MLP_10, @MLP_11
    


    The operational code that fetches starting location of a specific pattern (I use p_ to preface pointer variables):
    p_pats := @@ML_Pats[pattern]
    


    Finally, the bits from a step in the pattern are retrieved with:
    outs := long[p_pats]
    


    The variable p_pats gets incremented (by 4) for every step.
  • msrobotsmsrobots Posts: 3,709
    edited 2014-02-22 15:12
    But isn't long[@mailbox] exactly the same as mailbox without long[] and @?

    Enjoy!

    Mike
  • kuronekokuroneko Posts: 3,623
    edited 2014-02-22 15:44
    David Betz wrote: »
    Edit: Added @ in front of the mailbox references. That didn't fix the problem though.
    The current version should work (long[@mailbox] or just mailbox). Which suggests that you simply patch the wrong values. Have a play with this one:
    VAR
      long  stack[32]
      
    PUB null
    
      cognew(patch, @stack{0})
      dispatch
      
    PUB dispatch | params
    
      dira[16..23]~~
      
      repeat
        repeat until ([COLOR="#FF8C00"]params := mailbox[/COLOR])
    
        outa[16..23] := params
        
        mailbox := 0
    
    DAT
      mailbox long 0
    
    PRI patch : n
    
      repeat
        repeat while mailbox
        [COLOR="#FF8C00"]mailbox := ++n[/COLOR]
        waitcnt(clkfreq + cnt)
    
    DAT
    
    How do you patch mailbox and how do you prepare what is stored at that address?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 17:59
    msrobots wrote: »
    But isn't long[@mailbox] exactly the same as mailbox without long[] and @?

    Enjoy!

    Mike
    Now that I try it again I find I get the exact same result from long[long[@mailbox]] as with long[mailbox] as you suggest. Not sure why it didn't appear that way when I tried it earlier. I suspect I wasn't rebuilding correctly before. Thanks for mentioning this simplification!
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 18:10
    kuroneko wrote: »
    The current version should work (long[@mailbox] or just mailbox). Which suggests that you simply patch the wrong values. Have a play with this one:
    VAR
      long  stack[32]
      
    PUB null
    
      cognew(patch, @stack{0})
      dispatch
      
    PUB dispatch | params
    
      dira[16..23]~~
      
      repeat
        repeat until ([COLOR="#FF8C00"]params := mailbox[/COLOR])
    
        outa[16..23] := params
        
        mailbox := 0
    
    DAT
      mailbox long 0
    
    PRI patch : n
    
      repeat
        repeat while mailbox
        [COLOR="#FF8C00"]mailbox := ++n[/COLOR]
        waitcnt(clkfreq + cnt)
    
    DAT
    
    How do you patch mailbox and how do you prepare what is stored at that address?[/QUOTE
    This is an attempt to create a means to allow C++ programs to call Spin objects. It looks for all PUB methods in a Spin file and creates wrappers to call them from C. It patches the value of "mailbox" by parsing the binary file generated by OpenSpin. I'm pretty sure it is patching the correct value because I put a dummy constant in that location instead of zero and verified in the patching program that the correct value was at the address that I calculated from the binary file header.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 18:20
    Here is the code that patches the value of "mailbox". Actually, in this code I've renamed the variable to "p_mailbox" following JonnyMac's suggestion since it is actually a pointer to the mailbox. The "spinBinary" variable is the compiled binary for the Spin code with the first four bytes removed.
    test::test()
    {
      memset(m_variables, 0, sizeof(m_variables));
      if (m_cogid < 0) {
        Params *params = (Params *)spinBinary;
        uint16_t *dbase = (uint16_t *)(uint32_t)params->dbase;
        uint32_t *dat = (uint32_t *)(spinBinary + 0x0018);
        params->pbase += (uint16_t)(uint32_t)spinBinary - 4;
        params->vbase  = (uint16_t)(uint32_t)m_variables;
        params->dbase  = (uint16_t)(uint32_t)(m_stack + 2);
        params->pcurr += (uint16_t)(uint32_t)spinBinary - 4;
        params->dcurr  = params->dbase + 32;
        dbase[-4] = 2;          // pbase + abort-trap + return-value
        dbase[-3] = 0;          // vbase (not used)
        dbase[-2] = 0;          // dbase (not used)
        dbase[-1] = 0xfff9;     // return address
        *(uint32_t *)dbase = 0; // result
        dat[0] = (uint32_t)&m_mailbox;
        m_cogid = cognew(SPINVM, spinBinary);
      }
    }
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 18:55
    It turns out that this is really a C problem not a Spin problem.

    This code seems to work correctly:
    uint32_t test::set_pins(uint32_t pin1, uint32_t pin2)
    {
      uint32_t params[4];
      params[0] = (uint32_t)m_variables;
      params[1] = 1;
      params[2] = pin1;
      params[3] = pin2;
      printf("params %08x\n", (uint32_t)params);
      m_mailbox = params;
      while (m_mailbox)
        ;
      return params[0];
    }
    

    But this fails by passing a bad value in params[1]:
    uint32_t test::set_pins(uint32_t pin1, uint32_t pin2)
    {
      uint32_t params[4];
      params[0] = (uint32_t)m_variables;
      params[1] = 1;
      params[2] = pin1;
      params[3] = pin2;
      m_mailbox = params;
      while (m_mailbox)
        ;
      return params[0];
    }
    
    Adding the printf seems to make the program work. I'm not sure why. Here is the declaration of the class containing this method:
    class test {
    public:
      test();
      ~test();
      uint32_t set_pin(uint32_t pin);
      uint32_t set_pins(uint32_t pin1, uint32_t pin2);
      uint32_t swap_pins();
      uint32_t show_pins();
      uint32_t blink();
    private:
      uint8_t m_variables[16];
      static uint32_t m_stack[64];
      static uint32_t *volatile m_mailbox;
      static int m_cogid;
    };
    

    The code was compiled with the following command line:
    propeller-elf-gcc -Os -Wall -o test.elf test_main.cpp test.cpp -mno-fcache -fno-exceptions -fno-rtti
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 19:08
    It seems that without the printf the entire setup of the params array is being optimized away. I ended up having to add the following declaration to get this to work:
    volatile uint32_t *volatile test::m_mailbox = 0;
    
    It's important that both the pointer and the thing that it points to are both declared volatile. Anyway, the spinwrap program is now working for single Spin object instances. Thanks for all of the suggestions!
Sign In or Register to comment.