Shop OBEX P1 Docs P2 Docs Learn Events
SpinWrap - a tool for allowing C or C++ to use Spin Objects - Page 2 — Parallax Forums

SpinWrap - a tool for allowing C or C++ to use Spin Objects

245

Comments

  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-21 15:08
    Dave Hein wrote: »
    I looked at your code for setting up the Spin header, and I was confused at first until I realized that the first four bytes are missing. Because of this I think you will have to adjust the offset you add to PBASE and PCURR. It might be easier to include the first four bytes and not worry about the adjustment. Also, you are adding 4 to m_stack to get dbase, but m_stack is an int32 array, so that's adding 16 bytes. We should add 8 bytes to account for the initial stack frame, which is 2 int32's. Also, the space between dbase and dcurr should remain the same as it was in the original header. You are adding 32 to an int16 pointer, which is 64 bytes. I think it's better to compute the original difference between dbase and dcurr at the beginning, and then add it to the new dbase to get the new dcurr.

    Here are my suggested changes.
        Params *params = (Params *)spinBinary;
        uint16_t *dbase = (uint16_t *)(uint32_t)params->dbase;
        uint32_t *dat = (uint32_t *)(spinBinary + 0x001c);
        uint32_t space = params->dcurr - params->dbase;
        params->pbase += (uint16_t)spinBinary - 4;
        params->vbase  = (uint16_t)(uint32_t)m_variables;
        params->dbase  = (uint16_t)(uint32_t)(m_stack + 2);
        params->pcurr += (uint16_t)spinBinary - 4;
        params->dcurr  = params->dbase + space;
    
    Actually, I ended up doing things slightly differently. Here is the generate code:
        Params *params = (Params *)spinBinary;
        uint16_t *dbase = (uint16_t *)(uint32_t)params->dbase;
        uint32_t *dat = (uint32_t *)(spinBinary + 0x001c);
        params->pbase += (uint16_t)spinBinary - 4;
        params->vbase  = (uint16_t)(uint32_t)m_variables;
        params->dbase  = (uint16_t)(uint32_t)(m_stack + 2);
        params->pcurr += (uint16_t)spinBinary - 4;
        params->dcurr  = params->dbase + 32;
    
    However, the 32 constant in the last line is actually calculated by spinwrap by subtracting dbase from dcurr as you suggest. There is no need to do that calculation at runtime.

    I still need to figure out how to invoke a method of an arbitrary object instance. Right now I'm always calling a method of the first object instance that I create.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-21 15:30
    Yes, I see that the original difference between dbase and dcurr was 0x20 or 32. However, params->dbase is a uint16_t pointer, so "+ 32" applied to that is actually plus 64 bytes. It should be "+ 16" to add 32 bytes. Isn't C great? It automatically scales things to match the size of the type. Of course that means we have to undo the automatic scaling when we want to add byte offsets. I often cast the darn pointer to a char pointer or an int, add the offset, and then cast it back to the original pointer type.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-21 15:51
    Dave Hein wrote: »
    Yes, I see that the original difference between dbase and dcurr was 0x20 or 32. However, params->dbase is a uint16_t pointer, so "+ 32" applied to that is actually plus 64 bytes. It should be "+ 16" to add 32 bytes. Isn't C great? It automatically scales things to match the size of the type. Of course that means we have to undo the automatic scaling when we want to add byte offsets. I often cast the darn pointer to a char pointer or an int, add the offset, and then cast it back to the original pointer type.
    It's not a pointer. It's just a uint16_t. You can't use a pointer because that would be 32 bits wide.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-21 17:59
    Yes, you're right. So does the program work? Can you call Spin methods from C?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-21 18:40
    Dave Hein wrote: »
    Yes, you're right. So does the program work? Can you call Spin methods from C?
    I haven't tried running the code that it produces yet. I'm afraid it won't work and I'll have to debug it! :-)
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-21 20:12
    David Betz wrote: »
    I haven't tried running the code that it produces yet. I'm afraid it won't work and I'll have to debug it! :-)
    Okay, I tried it and it didn't work the first time. I guess I have some debugging to do.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 08:11
    I fixed a bunch of bugs and added some LED test code and it's starting to work. I'm at least running the Spin proxy code and am even able to invoke a method from the Spin object I'm trying to call. However, my mailbox interface doesn't seem to work correctly. No matter what value I pass as the method index it always seems to come through as zero.

    If I run this on a QuickStart board I end up with LEDs 16, 17, and 18 lit but the method I'm trying to invoke has the index 1 so it should light LED 19 instead of 18. Anyone see the problem?

    The Spin program I'm trying to invoke from C:
    VAR
    	long my_pin
    	long my_other_pin
    	
    PUB set_pin(pin)
        my_other_pin := my_pin
    	my_pin := pin
    
    PUB set_pins(pin1, pin2)
    	my_pin := pin1
    	my_other_pin := pin2
    
    PUB swap_pins | tmp
    	tmp := my_pin
    	my_pin := my_other_pin
    	my_other_pin := tmp
    
    PUB show_pins
    	outa[my_pin] := 1
    	outa[my_other_pin] := 0
    	dira[my_pin] := 1
    	dira[my_other_pin] := 1
    	
    PUB blink
    	repeat 5
    	    show_pins
    	    waitcnt(clkfreq / 2 + CNT)
    	    swap_pins
    

    The C test program that tries to invoke the Spin object:
    #include <propeller.h>
    #include "test.h"
    
    int main(void)
    {
        test obj;
    
        obj.set_pins(20, 21);
        obj.blink();
        obj.set_pin(22);
        obj.blink();
        
        while (1)
        	;
    
        return 0;
    }
    

    The generated Spin proxy code:
    ' This file was generated by spinwrap. Do not edit!
    
    OBJ
      x : "test"
    
    PUB dispatch | params, object, index, arg1, arg2, arg3, arg4
      repeat
        outa[16] := 1
        dira[16] := 1
        repeat while (params := long[mailbox]) == 0
        longmove(@object, params, 6)
        outa[17] := 1
        dira[17] := 1
        outa[18 + index] := 1
        dira[18 + index] := 1
        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
    

    The generated C++ header file:
    /* This file was generated by spinwrap. Do not edit! */
    
    #include <stdint.h>
    
    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 generated C++ stub code:
    /* This file was generated by spinwrap. Do not edit! */
    
    #include <propeller.h>
    #include <string.h>
    #include "test.h"
    
    #define SPINVM 0xf004
    
    uint32_t test::m_stack[];
    uint32_t *volatile test::m_mailbox = 0;
    int test::m_cogid = -1;
    
    static uint8_t spinBinary[] = {
     0x00, 0xfd, 0x10, 0x00, 0xe8, 0x00, 0xf8, 0x00, 0x20, 0x00, 0x18, 0x01, 0x88, 0x00, 0x02, 0x01,
     0x10, 0x00, 0x1c, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x37, 0x03, 0x3d,
     0xb4, 0x36, 0x37, 0x03, 0x3d, 0xb6, 0xc4, 0x0c, 0xc0, 0x66, 0x80, 0x35, 0xfc, 0x0a, 0x02, 0x04,
     0x75, 0x6b, 0x64, 0x38, 0x06, 0x1e, 0x36, 0x38, 0x11, 0x3d, 0xb4, 0x36, 0x38, 0x11, 0x3d, 0xb6,
     0x36, 0x38, 0x12, 0x6c, 0xec, 0x3d, 0xb4, 0x36, 0x38, 0x12, 0x6c, 0xec, 0x3d, 0xb6, 0x38, 0x7b,
     0x6c, 0x35, 0x0d, 0x12, 0x36, 0x0d, 0x16, 0x37, 0x00, 0x0d, 0x1a, 0x37, 0x21, 0x0d, 0x1c, 0x37,
     0x01, 0x0d, 0x1e, 0x34, 0x61, 0x0c, 0x00, 0x70, 0x06, 0x02, 0x01, 0x61, 0x0c, 0x00, 0x70, 0x74,
     0x06, 0x02, 0x02, 0x61, 0x0c, 0x00, 0x06, 0x02, 0x03, 0x61, 0x0c, 0x00, 0x06, 0x02, 0x04, 0x61,
     0x0c, 0x00, 0x06, 0x02, 0x05, 0x61, 0x0c, 0x60, 0x64, 0xc1, 0x35, 0xc4, 0x0c, 0xc1, 0x04, 0xff,
     0x8b, 0x32, 0x00, 0x00, 0x50, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
     0x22, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x40, 0x45, 0x64, 0x41,
     0x32, 0x64, 0x41, 0x68, 0x45, 0x32, 0x40, 0x65, 0x44, 0x41, 0x64, 0x45, 0x32, 0x36, 0x40, 0x3d,
     0xb4, 0x35, 0x44, 0x3d, 0xb4, 0x36, 0x40, 0x3d, 0xb6, 0x36, 0x44, 0x3d, 0xb6, 0x32, 0x38, 0x05,
     0x08, 0x11, 0x01, 0x05, 0x04, 0x35, 0xc0, 0x37, 0x00, 0xf6, 0x3f, 0x91, 0xec, 0x23, 0x01, 0x05,
     0x03, 0x09, 0x6f, 0x32,
    };
    
    typedef struct {
      uint16_t unused;
      uint16_t pbase;
      uint16_t vbase;
      uint16_t dbase;
      uint16_t pcurr;
      uint16_t dcurr;
    } Params;
    
    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);
      }
    }
    
    test::~test()
    {
      if (m_cogid >= 0) {
        cogstop(m_cogid);
        m_cogid = -1;
      }
    }
    
    uint32_t test::set_pin(uint32_t pin)
    {
      uint32_t params[3];
      params[0] = (uint32_t)m_variables;
      params[1] = 0;
      params[2] = pin;
      m_mailbox = params;
      while (m_mailbox)
        ;
      return params[0];
    }
    
    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];
    }
    
    uint32_t test::swap_pins()
    {
      uint32_t params[2];
      params[0] = (uint32_t)m_variables;
      params[1] = 2;
      m_mailbox = params;
      while (m_mailbox)
        ;
      return params[0];
    }
    
    uint32_t test::show_pins()
    {
      uint32_t params[2];
      params[0] = (uint32_t)m_variables;
      params[1] = 3;
      m_mailbox = params;
      while (m_mailbox)
        ;
      return params[0];
    }
    
    uint32_t test::blink()
    {
      uint32_t params[2];
      params[0] = (uint32_t)m_variables;
      params[1] = 4;
      m_mailbox = params;
      while (m_mailbox)
        ;
      return params[0];
    }
    

    Finally, I've attached the spinwrap.c code.

    spinwrap.c
    c
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 19:17
    I got the spinwrap program working. This example now works:

    C++ program calling a Spin object:
    #include <propeller.h>
    #include "test.h"
    
    int main(void)
    {
        test obj;
    
        obj.set_pins(20, 21);
        obj.blink();
        obj.set_pin(22);
        obj.blink();
        
        while (1)
        	;
    
        return 0;
    }
    

    Spin object being called:
    VAR
    	long my_pin
    	long my_other_pin
    	
    PUB set_pin(pin)
        my_other_pin := my_pin
    	my_pin := pin
    
    PUB set_pins(pin1, pin2)
    	my_pin := pin1
    	my_other_pin := pin2
    
    PUB swap_pins | tmp
    	tmp := my_pin
    	my_pin := my_other_pin
    	my_other_pin := tmp
    
    PUB show_pins
    	outa[my_pin] := 1
    	outa[my_other_pin] := 0
    	dira[my_pin] := 1
    	dira[my_other_pin] := 1
    	
    PUB blink
    	repeat 5
    	    show_pins
    	    waitcnt(clkfreq / 2 + CNT)
    	    swap_pins
    

    The spinwrap program takes as input the Spin object source file and produces a C++ class and a Spin proxy that calls the Spin object methods. It uses OpenSpin to compile the Spin proxy. I've attached the source for the working version of spinwrap.c. It is currently setup to work on the Mac but the only thing that should need to be changed to run under Windows or Linux is the name of the OpenSpin binary. I have it set to "openspin.osx" for the Mac but "openspin.exe" or just "openspin" should work for Windows and "openspin.linux" for Linux. I'll make that automatic in a future version of the code.

    However, this version only works with a single instance of the Spin object. The C++ wrappers pass a pointer to a separate VAR section for each C++ instance of the Spin object but the Spin proxy doesn't do anything with that value. That means that it always uses the VARs for the first object created when the proxy program is first launched in a COG. I'd appreciate some help figuring out how to patch in the VAR pointer for other instances. I assume that I'd do this by patching the object table of the proxy object but I'm not sure how to do that since the object reference in the object table is an offset not an absolute address.

    spinwrap.c
    c
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-22 19:27
    Congratulations! Spinwrap will be a useful tool for interfacing C/C++ code to the Spin objects in the OBEX. It's another nice addition to the Prop toolbox.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 19:37
    Dave Hein wrote: »
    Congratulations! Spinwrap will be a useful tool for interfacing C/C++ code to the Spin objects in the OBEX. It's another nice addition to the Prop toolbox.
    Thanks but I'm not sure it's really the right way to do this. The more I think about it the more I think that spin2cpp is a better way of doing this. The spinwrap tool creates C++ wrappers to call a Spin object that runs in another COG. However, given the structure of most OBEX objects, that Spin code probably has Spin wrappers to call PASM code. This means there are two levels of wrappers in the spinwrap solution where there is only one in the spin2cpp solution since the C++ wrappers get linked with the code that calls them. Does anyone see any reason that someone would want to choose spinwrap over spin2cpp? I can't really think of any advantages to the spinwrap approach.

    Also, spinwrap is a proof of concept. Its parser is very dumb and only scans the Spin source files for PUB statements. It doesn't really understand Spin syntax especially comment syntax so it may find commented out PUB statements as well as live ones. Lastly, it doesn't parse the CON statements in the Spin source file but it should make CON values available to the C++ code like Spin does using the # syntax. Lastly, as I mentioned earlier, it currently only handles a single instance of the Spin object. I think that can be fixed but I'm wondering how far to take this given that it seems spin2cpp is a better solution.

    Any opinions?

    In the meantime, I've attached a zip file containing the source, a Makefile to build it, and the sample I've been using to test it.

    spinwrap.zip
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-22 19:41
    One more thing, if it turns out that this ends up being a useful tool, I can relatively easily add an option to generate C code so it can work with Catalina C.
  • jazzedjazzed Posts: 11,803
    edited 2014-02-22 20:35
    Congrats David.

    I'll do some integration testing tomorrow if possible and post some results.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-23 12:07
    I got multiple object instances to work this morning. I've attached an updated zip file with the spinwrap tool as well as a simple test program that shows using multiple instances.

    C++ test program:
    #include <propeller.h>
    #include "test.h"
    
    int main(void)
    {
        test obj;
        test obj2;
    
        obj.set_pins(16, 17);
        obj.blink();
        obj.set_pin(18);
        obj.blink();
    
        obj2.set_pins(20, 21);
        obj2.blink();
        obj2.set_pin(22);
        obj2.blink();
        
        obj.blink();
        obj2.blink();
    
        while (1)
        	;
    
        return 0;
    }
    

    Spin object:
    VAR
    	long my_pin
    	long my_other_pin
    	
    PUB set_pin(pin)
        my_other_pin := my_pin
    	my_pin := pin
    
    PUB set_pins(pin1, pin2)
    	my_pin := pin1
    	my_other_pin := pin2
    
    PUB swap_pins | tmp
    	tmp := my_pin
    	my_pin := my_other_pin
    	my_other_pin := tmp
    
    PUB show_pins
    	outa[my_pin] := 1
    	outa[my_other_pin] := 0
    	dira[my_pin] := 1
    	dira[my_other_pin] := 1
    	
    PUB blink
    	repeat 5
    	    show_pins
    	    waitcnt(clkfreq / 2 + CNT)
    	    swap_pins
    

    spinwrap.zip
  • jazzedjazzed Posts: 11,803
    edited 2014-02-23 13:00
    Thanks David.

    I'll try testing this in SimpleIDE today.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-23 13:03
    jazzed wrote: »
    Thanks David.

    I'll try testing this in SimpleIDE today.
    Thanks Steve. At the moment the spinwrap program writes its output files to the current directory. Will you need a -o option to redirect to a different output directory? That wouldn't be too hard to add.

    Running spinwrap on a .spin file produces two primary output files: a .h file containing the C++ class definition of the wrapper code and a .cpp file containing the wrapper code itself. Those files will need to be included in any SimpleIDE project that wants to use the Spin object. The spinwrap program also produces a .spin file containing the proxy code for calling the Spin object from C++ and a .binary file which is the result of compiling the proxy and the spin object with OpenSpin. Those files are not needed in the SimpleIDE project and should probably be automatically removed by the spinwrap tool.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-23 17:54
    Steve has been playing with my spinwrap code and has been having some problems trying to run the VGA_Text_Demo.spin program. I guess I'm hoping Dave Hein will chime in here. Do you know of any reason why the VGA text demo wouldn't work with the scheme I'm using to load and run Spin objects? One thing I wonder about is the nested Spin objects. In my test program I have a main proxy program that has one object and no sub-objects but the VGA text demo has VGA_TextDemo which includes VGA_Text which includes VGA. Are there any special considerations for relocating an object with nested objects that my code is missing?

    Thanks!
    David
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-23 19:19
    It works OK for me -- at least in LMM mode. CMM didn't work for some reason. I just had to add the following main routine to the generated VGA_Text_Demo.cpp file.
    int main()
    {
        VGA_Text_Demo xyz;
    
        xyz.start();
        return 0;
    }
    
    Also, I don't have OpenSpin on my system, so I used bstc instead. I ran this on my C3 board, so I also had to add "DIRA |= $8000" at the beginning of the start method in VGA_Text_Demo.spin.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-23 19:59
    I tried converting VGA_Text_Demo.spin to C, and making VGA_Text.spin the top object, and I get different results. It worked in CMM mode, but not in LMM. My main routine was this:
    int main()
    {
        int i;
        VGA_Text text;
        char *tststr = "Now is the time";
    
        DIRA |= 0x8000;
    
        //start term
        text.start(16);
        text.str((int)"\r   VGA Text Demo...\r\r\014\005 OBJ and VAR require only 2.6KB \014\001");
        for (i = 0; i < 14; i++)
            text.out(' ');
        for (i = 0x0E; i <= 0xFF; i++)
            text.out(i);
        text.str((int)"\014\006     Uses internal ROM font     \014\002");
        while (1)
        {
            text.str((int)"\012\014\013\016");
            text.hex(i++, 8);
        }
        return 0;
    }
    
    I found that calling text.out worked OK in LMM, but text.str did not. I tried turning optimization of with -O0, and neither CMM or LMM worked. So there's something odd going on, but I don't know exactly what it is.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-23 20:15
    Dave Hein wrote: »
    I tried converting VGA_Text_Demo.spin to C, and making VGA_Text.spin the top object, and I get different results. It worked in CMM mode, but not in LMM. My main routine was this:
    int main()
    {
        int i;
        VGA_Text text;
        char *tststr = "Now is the time";
    
        DIRA |= 0x8000;
    
        //start term
        text.start(16);
        text.str((int)"\r   VGA Text Demo...\r\r\014\005 OBJ and VAR require only 2.6KB \014\001");
        for (i = 0; i < 14; i++)
            text.out(' ');
        for (i = 0x0E; i <= 0xFF; i++)
            text.out(i);
        text.str((int)"\014\006     Uses internal ROM font     \014\002");
        while (1)
        {
            text.str((int)"\012\014\013\016");
            text.hex(i++, 8);
        }
        return 0;
    }
    
    I found that calling text.out worked OK in LMM, but text.str did not. I tried turning optimization of with -O0, and neither CMM or LMM worked. So there's something odd going on, but I don't know exactly what it is.
    Thanks for trying. I see now that Steve was building in LMM mode with no optimization. I tried switching to CMM mode with -Os and now the screen gets cleared to blank but the demo still doesn't show up. I guess there is a bug in spinwrap somewhere. By the way, I've checked spinwrap into the propgcc project under propgcc/demos/spinwrap. The version that is there has a few extra features like the ability to specify a different output path and a way to pass parameters that get used in the invocation of openspin. That is where I'll be making future changes rather than posting the sources to the forum.

    Thanks for helping!

    David
  • jazzedjazzed Posts: 11,803
    edited 2014-02-23 20:36
    Hi David.

    The VGA_Text_Demo works for me with LMM mode now. The CMM variety is missing the palette colors for some reason.

    Here's my main.c
    #include "VGA_Text_Demo.h"
    
    
    int main(void)
    {
        VGA_Text_Demo vga;
    
    
        vga.start();
        return 0;
    }
    
    Here's my VGA_Text_Demo.spin
    ''***************************************
    ''*  VGA Text Demo v1.0                 *
    ''*  Author: Chip Gracey                *
    ''*  Copyright (c) 2006 Parallax, Inc.  *
    ''*  See end of file for terms of use.  *
    ''***************************************
    
    
    CON
    
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    
    OBJ
    
    
      text : "VGA_Text"
    
    
    VAR
      long stack[8]
    
    
    PUB start | i
    
    
      outa := 0
      dira |= $8000
      'cognew(blink, @stack) ' uncomment to blink the screen
      text.start(16)
    
    
      text.str(string(13,"   VGA Text Demo...",13,13,$C,5," OBJ and VAR require only 2.6KB ",$C,1))
      repeat 14
        text.out(" ")
      repeat i from $0E to $FF
        text.out(i)
      text.str(string($C,6,"     Uses internal ROM font     ",$C,2))
      repeat
        text.str(string($A,12,$B,14))
        text.hex(i++, 8)
    
    
    PUB blink
      dira |= $8000
      repeat
        waitcnt(CLKFREQ<<3+CNT)
        outa ^= $8000
        waitcnt(CLKFREQ+CNT)
        outa ^= $8000
    
    Here's my build.sh script:
    #!/bin/sh
    SPIN=$1
    MAIN=main
    MEMM=lmm
    FLGS="-fno-rtti -fno-exceptions -Os"
    ./spinwrap -S,-L/home/steve/Projects/spinside/spin ./${SPIN}.spin
    propeller-elf-g++ ${FLGS} -m${MEMM} -c ${SPIN}.cpp
    propeller-elf-g++ ${FLGS} -m${MEMM} -o ${MAIN}.elf ${MAIN}.c ${SPIN}.o
    propeller-load -r ${MAIN}.elf
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-24 03:53
    jazzed wrote: »
    Hi David.

    The VGA_Text_Demo works for me with LMM mode now. The CMM variety is missing the palette colors for some reason.
    How come you changed dira[15] to using an explicit bit mask? Was that necessary to get it working?

    It's great that you were able to get this working but there is clearly something wrong with the way I'm loading and starting the Spin code. You shouldn't have to tweak this program to get it to work. I'll try to take a look at my code to make sure I'm getting all of the offsets right but it may not be for a few days. Sorry for the trouble you're having with this!!
  • jazzedjazzed Posts: 11,803
    edited 2014-02-24 08:41
    David Betz wrote: »
    How come you changed dira[15] to using an explicit bit mask? Was that necessary to get it working?

    It's just easier for me to understand :)
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-24 08:46
    jazzed wrote: »
    It's just easier for me to understand :)
    That's a relief. I thought maybe one way worked and the other didn't. I'm not sure what could have caused that! :-)
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-24 20:08
    Dave Hein: I'm trying to debug the VGA demo problem and am wondering about the following code in an example you posted:
      ' Zero the VAR area
      longfill(vbase, 0, (dbase - vbase - 8) >> 2)
    
    Where does the -8 come from? I've been calculating the size of the VAR area of an object by using dbase-vbase. Is the -8 because of the $fff9, 0, 0, 2 prefix to the return value that starts at dbase[0]? If so, I guess I'm allocating 8 too many bytes for the VAR space and 8 too few bytes for the stack. Maybe that's my problem.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-24 20:17
    David Betz wrote: »
    Dave Hein: I'm trying to debug the VGA demo problem and am wondering about the following code in an example you posted:
      ' Zero the VAR area
      longfill(vbase, 0, (dbase - vbase - 8) >> 2)
    
    Where does the -8 come from? I've been calculating the size of the VAR area of an object by using dbase-vbase. Is the -8 because of the $fff9, 0, 0, 2 prefix to the return value that starts at dbase[0]? If so, I guess I'm allocating 8 too many bytes for the VAR space and 8 too few bytes for the stack. Maybe that's my problem.
    Never mind. I answered my own question. I was allocating 8 bytes too much for the VAR area but that wasn't causing my problem. I had ordered a few statements wrong and was ending up setting up the initial stack incorrectly. I fixed the bug and now the VGA_Text_Demo works fine.
  • jazzedjazzed Posts: 11,803
    edited 2014-02-24 20:46
    David Betz wrote: »
    Never mind. I answered my own question. I was allocating 8 bytes too much for the VAR area but that wasn't causing my problem. I had ordered a few statements wrong and was ending up setting up the initial stack incorrectly. I fixed the bug and now the VGA_Text_Demo works fine.
    Cool. Good fun David!

    Yes, it works with CMM and LMM memory models. I'll do more testing now.
  • RossHRossH Posts: 5,462
    edited 2014-02-25 02:54
    David Betz wrote: »
    One more thing, if it turns out that this ends up being a useful tool, I can relatively easily add an option to generate C code so it can work with Catalina C.

    Good stuff, David!
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-25 03:35
    RossH wrote: »
    Good stuff, David!
    Thanks Ross! It would be relatively easy to make it generate C code as an option if you think it would be of some value to Catalina programmers.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-25 04:28
    Glad you found the problem. I had noticed the other issue about the extra 8 bytes in the VAR area. I guess I should have mentioned that earlier, but like you said it shouldn't cause any problems except for wasting 8 bytes.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-02-25 04:52
    I just pushed a new version of spinwrap that supports a -c option to generate C code instead of C++. I've tried this under PropGCC but haven't had a chance to try it under Catalina yet. I've attached a zip file containing the code for those who might not want to check out all of propgcc just to get this.

    spinwrap.zip
Sign In or Register to comment.