Shop OBEX P1 Docs P2 Docs Learn Events
Catalina 2.6 - a FREE C compiler for the Propeller - The Final Frontier! - Page 19 — Parallax Forums

Catalina 2.6 - a FREE C compiler for the Propeller - The Final Frontier!

11415161719

Comments

  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-14 00:14
    Thanks++ to jazzed!

    Re cutting and pasting, that sounds tedious! Every time I do something manually I'm also automating it in the IDE. I guess that is why it is taking so long to get some quite simple things working here. Hopefully only a few days away from talking to and from the registry.
  • Heater.Heater. Posts: 21,230
    edited 2010-12-14 00:19
    You can also use BradC's command line compiler BSTC to extract PASM compiled into binary blobs from Spin files. With a couple of command line options which I don't remember off hand.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-14 00:36
    Great to hear there are other options - thanks heater. I'm already reading binary files as part of the xmodem transfer, so if these options had not existed it would have been possible to discard the first n bytes before doing the transfer. But these pre-written ones are going to be easier - just add one line to a batch file.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-15 00:27
    Ok, decoding what this all does.

    Running Spinc creates a .h file that looks like this:
    /** 
     * @file COGJECT_array.h
     * Created with spin.binary PASM to C Array Converter.
     * Copyright (c) 2010, John Doe
     */
    unsigned long COGJECT_array[] =
    {
        0xa0fc0441, 0x5c7c0000, 0x00007530
    };
    

    This appears to be the core of the original binary with 18 bytes stripped off the beginning and 8 bytes removed from the end. I understand the 18 bytes at the beginning being removed but I do not understand the 8 bytes at the end. Is it always 8 bytes regardless of the program?

    Next- a big picture question. We have a .h file that is written in C (as an aside, this appears to be the C equivalent of the BASIC Data statement, and I've been looking for this syntax for a long time!).

    How do we use this?

    The idea I had is to create a binary file, ending in the extension .cog, that resides on the sd card and can be loaded into a cog.

    Now I am thinking that in addition to this, maybe there is another way?

    Because including fopen and fclose and other stdio commands in a c program made it a lot bigger, so big that it only can be run in XMM, I believe that this ties future development to XMM only platforms. Maybe this is not correct, but assuming this is the development path for the moment, what it means is that is a much lower cost for a piece of 2k cog code. 2k out of 32k on the propeller is a significant percentage. 2k out of 512k (or 32Mb) is much less significant.

    Therefore, it could be quite possible to include code for, say, three different types of VGA drivers, inside a C program - either as standard code, or as included .h files.

    So even though sd card access of cog code is quite easy to do, maybe it is better to include the code in the program. I am presuming that loading a cog then becomes as simple as doing a 'coginit' and pointing it at the array in the .h file?

    I need to think more about the options here, eg how many cogjects might one ever want to conceivably use? Even if you had 50, that is only 100k out of 512k. Though I might be using more like 10-15.
  • kuronekokuroneko Posts: 3,623
    edited 2010-12-15 00:43
    Dr_Acula wrote: »
    This appears to be the core of the original binary with 18 bytes stripped off the beginning and 8 bytes removed from the end. I understand the 18 bytes at the beginning being removed but I do not understand the 8 bytes at the end. Is it always 8 bytes regardless of the program?
    It's neither always $18 nor 8. It all depends on how many methods and objects were used to create the binary (you may have included an object which only holds constants etc). SPIN code itself follows DAT sections so there is your post-DAT tail. Best to leave it to the extractor tools ;)
    Dr_Acula wrote: »
    Because including fopen and fclose and other stdio commands in a c program made it a lot bigger, so big that it only can be run in XMM, I believe that this ties future development to XMM only platforms. Maybe this is not correct, but assuming this is the development path for the moment, what it means is that is a much lower cost for a piece of 2k cog code. 2k out of 32k on the propeller is a significant percentage. 2k out of 512k (or 32Mb) is much less significant.
    Note that not every cog binary is 2K in size. For example the 3 built-in cog binaries in my current project only amount to 1008 bytes. So 2K each may be a rather pessimistic view.
  • mparkmpark Posts: 1,318
    edited 2010-12-15 00:49
    Heater. wrote: »
    You can also use BradC's command line compiler BSTC to extract PASM compiled into binary blobs from Spin files. With a couple of command line options which I don't remember off hand.

    Homespun will offer similar functionality real soon now.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-15 01:50
    Thanks for the hints. Yes, best to leave it to the extractor tools.

    I've added spinc into the batch file (it could also be BSTC).

    This is a technical question for RossH, but I presume the .h file needs to be moved to the "include" folder, not my working "demos" folder?

    Next step with "one click" pasm object creator is to add in some code to the main C program - the #include statement and a new function with the reference to the array and which loads it. My test program is called cogject.spin, the array created by spinc is called
    unsigned long COGJECT_array[] and now I need a function:
    void load_cogject()
    which I think just needs to do a coginit pointing to the cogject_array.

    Almost there with one keypress cogject creation...

    addit: The following is being created with a few keypresses. I put the .h program in comments to remind me what it looks like. Now I'm a little stuck with the exact syntax for _coginit. From the catalina manual

    int _coginit(int par, int addr, int cogid);
    This function starts a new cog. The par and addr parameters must be
    given as long addresses (which can easily be done by dividing the
    normal byte addresses by 4). The cogid parameter can be a specific
    cog, or the special value ANY_COG.


    but I'm not quite sure what 'par' is, and whether I need to pass addr as the name of the array storing the data, or whether it has a * for a pointer.

    Skeleton code below
    #include <stdio.h>
    #include <cogject.h> 
    
    /*
    unsigned long COGJECT_array[] =
    {
        0xa0fc0441, 0x5c7c0000, 0x00007530
    };
    */
    
    void load_cogject()
    {
    		//       _coginit(int par, int addr, int cogid);  // not sure about the syntax here
    		// par = ?, addr = cogject_array, cogid = 1?
    }
    
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                  t_setpos(0,0,i);                                       // move cursor to next line
                  t_color(0,0x08FC);                                     // RRGGBBxx eg dark blue background 00001000 white text 11111100
           }
    }
    
    void main ()
    {
           clearscreen();
           printf("Hello, World!\n");
           while (1);                                                    // Prop reboots on exit from main()!
    }
    

    help with the coginit line would be most appreciated (assuming this idea will actually load a cog!).
  • RossHRossH Posts: 5,580
    edited 2010-12-15 14:02
    Dr_Acula wrote: »
    Thanks for the hints. Yes, best to leave it to the extractor tools.

    I've added spinc into the batch file (it could also be BSTC).

    This is a technical question for RossH, but I presume the .h file needs to be moved to the "include" folder, not my working "demos" folder?

    No - you can leave the header file in your working folder. But you say:
    #include "header.h"
    
    instead of
    #include <header.h>
    
    Dr_Acula wrote: »
    Next step with "one click" pasm object creator is to add in some code to the main C program - the #include statement and a new function with the reference to the array and which loads it. My test program is called cogject.spin, the array created by spinc is called
    unsigned long COGJECT_array[] and now I need a function:
    void load_cogject()
    which I think just needs to do a coginit pointing to the cogject_array.
    Correct - see the program test_spinc.c in the Catalina\demos\spinc subdirectory.
    Dr_Acula wrote: »
    Almost there with one keypress cogject creation...

    addit: The following is being created with a few keypresses. I put the .h program in comments to remind me what it looks like. Now I'm a little stuck with the exact syntax for _coginit. From the catalina manual

    int _coginit(int par, int addr, int cogid);
    This function starts a new cog. The par and addr parameters must be
    given as long addresses (which can easily be done by dividing the
    normal byte addresses by 4). The cogid parameter can be a specific
    cog, or the special value ANY_COG.

    but I'm not quite sure what 'par' is, and whether I need to pass addr as the name of the array storing the data, or whether it has a * for a pointer.
    As above - see the program test_spinc.c in the Catalina\demos\spinc subdirectory for a working example.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-15 15:17
    Thanks Ross.

    Found the test_spinc file. I also read the readme.txt file - I'm doing option 3. So - your spinc code
    /*
     * Include the cog program formatted into a C arrary. The include file can 
     * be generated using the following commands:
     *
     *       homespun flash_led.spin -b
     *       spinc flash_led.binary > flash_led_array.h
     */
    #include "flash_led_array.h"
    
    
    /*
     * Include the cog function definitions
     */
    #include <catalina_cog.h>
    
    
    /*
     * This is an example of how to format data to be passed tothe cog program 
     * (via the usual PAR parameter). Note this is an example only - the flash_led 
     * cog program does not actually expect any data.
     */ 
    unsigned long data[] = { 1, 2, 3 };
    
    
    /*
     * The main C program - loads the cog program, then loops forever
     */
    void main() {
    
    
       if (_coginit ((int)data>>2, (int)flash_led_array>>2, ANY_COG) == -1) {
          // LED should start flashing on success - turn it
          // on and leave it to indicate a coginit failure
          _dira(1, 1);
          _outa(1, 1);
       }
    
       while (1) {
          // loop forever - flash led cog should continue running
       }
    }
    

    1) I take it that PAR is a series of parameters being passed to the cog. For the moment, can I just include the data array as a dummy array with your values 1,2,3? Does it always have three longs?

    2) Each cogject will have a different PAR data array - would I be better off renaming these from data[] to something like, mycogject_par[]

    3) Re (int)data>>2. Can we break that down into components, for a C newbie like me? I think there might be three things going on there -
    i) a shift, two bits to the right. Can you explain this more?
    ii) a conversion to an integer type. I'm not sure what is being converted here - is it the pointer to the data[] array?
    iii) an implicit conversion to a pointer to the data[] array. Forgive my confusion regarding pointers - I think I understand pointers where the * and & are used, but I still get confused about pointers that are implied, like pointers to arrays.

    4) (int)flash_led_array>>2
    i) again, what is the shift for?
    ii) flash_led_array is the same name as the .h file. Presumably this is the same as the name of the array within the .h file. But just to clarify, does this have to be the same as the .h name or the same as the array within the .h file?

    Many thanks in advance.

    eg
    #include <stdio.h>
    #include <cogject.h>
    
    unsigned long par_cogject[] = { 1, 2, 3 };   // data to pass to cog - ignore if not used
    
    void load_cogject()
    {
           _coginit((int)par_cogject>>2, (int)cogject_array>>2, 7);    // load into cog 7
    
    }
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                  t_setpos(0,0,i);                                       // move cursor to next line
                  t_color(0,0x08FC);                                     // RRGGBBxx eg dark blue background 00001000 white text 11111100
           }
    }
    
    void main ()
    {
           clearscreen();
           printf("Hello, World!\n");
           while (1);                                                    // Prop reboots on exit from main()!
    }
    

    where cogject.h is this
    /** 
     * @file COGJECT_array.h
     * Created with spin.binary PASM to C Array Converter.
     * Copyright (c) 2010, John Doe
     */
    unsigned long COGJECT_array[] =
    {
        0xa0fc0441, 0x5c7c0000, 0x00007530
    };
    

    ADDIT
    worked out 4 ii) - it is the array name within the file, AND it is case sensitive. testing this out now - it is almost compiling


    ADDIT again.

    I have a program that compiles, but it is not quite working yet. The .h file is as above and the program is thus:
    /* Cog test program - see bottom of code for the Main function */
    
    #include <stdio.h>
    #include <cogject.h>
    
    unsigned long par_cogject[] = { 1, 2, 3 };                           // data to pass to cog - ignore if not used
    
    void load_cogject()
    {
           _coginit((int)par_cogject>>2, (int)cogject_array>>2, 7);      // load into cog 7
           
    }
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                  t_setpos(0,0,i);                                       // move cursor to next line */
                  t_color(0,0x08FC);                                     // RRGGBBxx eg dark blue background 00001000 white text 11111100 
           }
    }
    
    void stopcog(int cognumber)                                          // stop a cog
    {
           _cogstop(cognumber);
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void fill_memory(int start_address,int finish_address,char value)    // fill memory with these bytes
    {
           int i;
           for(i=start_address;i <= finish_address;i++)
           {
                  poke(i,value);   
           }
    }
    void main () 
    {
           char c;     
           int i;     
           clearscreen();
           printf("Hello, World!\n");
           printf("Clock speed %u \n",_clockfreq());                       // see page 28 of the propeller manual for other useful commands
           printf("Catalina running in cog number %i \n",_cogid());        // integer
           i=30000;								// location to peek and poke
    	poke(i,66);								// poke a B, the cog should change this to an A
           printf("load cogject into cog 7\n");
           load_cogject();
           sleep(1000);                                                  // delay while cog gets started
           c=peek(i);                                                    // peek byte at this location
           printf("Peek value at %i = character %c Ascii value %d \n",i,c,c);                            
           while (1);                                                     // Prop reboots on exit from main() so stop this
    }
    

    pasm part is
    CON
      _clkfreq = 80_000_000
      _clkmode = xtal1 + pll16x
    
    PUB Main
        coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value
    
    DAT
                      org 0
    cogstart 
                      mov testvariable,#65   ' test value A
                      jmp #cogstart
    
    
    testvariable      long    $7530           ' test memory location 30000
                      fit 496
    
  • RossHRossH Posts: 5,580
    edited 2010-12-15 15:59
    Dr_Acula wrote: »
    Thanks Ross.

    1) I take it that PAR is a series of parameters being passed to the cog. For the moment, can I just include the data array as a dummy array with your values 1,2,3? Does it always have three longs?
    It doesn't have to be anything - that was just an example.
    Dr_Acula wrote: »

    2) Each cogject will have a different PAR data array - would I be better off renaming these from data[] to something like, mycogject_par[]
    If you want.
    Dr_Acula wrote: »


    3) Re (int)data>>2. Can we break that down into components, for a C newbie like me? I think there might be three things going on there -
    i) a shift, two bits to the right. Can you explain this more?
    Shift to the right by 2 is just divide by 4 - i.e. convert a byte address to a long address. I probably should have hidden this level of detail within the coginit function - or you could hide it in your own version of coginit. For more information, see the Parallax documentation (look at the PASM version of coginit, not the SPIN version).
    Dr_Acula wrote: »
    ii) a conversion to an integer type. I'm not sure what is being converted here - is it the pointer to the data[] array?
    Yes. My version coginit function expects ints. The parameters are usually addresses - but the par parameter in particular can just be any 14 bit value. Agian, you could hide this detail in your own version of coginit.
    Dr_Acula wrote: »
    iii) an implicit conversion to a pointer to the data[] array. Forgive my confusion regarding pointers - I think I understand pointers where the * and & are used, but I still get confused about pointers that are implied, like pointers to arrays.
    In C the name of an array is a pointer to the first element - so data is in fact a long *.
    Dr_Acula wrote: »
    4) (int)flash_led_array>>2
    i) again, what is the shift for?
    As above - to convert a byte address to a long address.
    Dr_Acula wrote: »
    ii) flash_led_array is the same name as the .h file. Presumably this is the same as the name of the array within the .h file. But just to clarify, does this have to be the same as the .h name or the same as the array within the .h file?
    No - it just makes things easier to understand.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-15 16:16
    Thanks for all that. Things like the >> are now one button copy and paste exercises, so I'll leave it as it is.

    Code compiles but the cog is not doing what it is supposed to do. This is getting close now, and it probably is just one tiny little mistake. Can you take a look at this and see what you think:

    pasm code
    CON
      _clkfreq = 80_000_000
      _clkmode = xtal1 + pll16x
    
    PUB Main
        coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value
    
    DAT
                      org 0
    cogstart 
                      mov testvariable,#65   ' test value A
                      jmp #cogstart
    
    
    testvariable      long    5000           ' test memory location 5000
                      fit 496
    

    .h code, filename is cogject.h
    /** 
     * @file cogject_array.h
     * Created with spin.binary PASM to C Array Converter.
     * Copyright (c) 2010, John Doe
     */
    unsigned long cogject_array[] =
    {
        0xa0fc0441, 0x5c7c0000, 0x00001388
    };
    

    and the program to run this
    /* Cog test program - see bottom of code for the Main function */
    
    #include <stdio.h>
    #include <cogject.h>
    
    unsigned long par_cogject[] = { 1, 2, 3 };                           // data to pass to cog - ignore if not used
    
    void load_cogject()
    {
           _coginit((int)par_cogject>>2, (int)cogject_array>>2, 7);      // load into cog 7
           
    }
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                  t_setpos(0,0,i);                                       // move cursor to next line */
                  t_color(0,0x08FC);                                     // RRGGBBxx eg dark blue background 00001000 white text 11111100 
           }
    }
    
    void stopcog(int cognumber)                                          // stop a cog
    {
           _cogstop(cognumber);
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void fill_memory(int start_address,int finish_address,char value)    // fill memory with these bytes
    {
           int i;
           for(i=start_address;i <= finish_address;i++)
           {
                  poke(i,value);   
           }
    }
    void main () 
    {
           char c;     
           int i;     
           clearscreen();
           printf("Hello, World!\n");
           printf("Clock speed %u \n",_clockfreq());                       // see page 28 of the propeller manual for other useful commands
           printf("Catalina running in cog number %i \n",_cogid());        // integer
           i=5000;								// location to peek and poke
    	poke(i,66);								// poke a B, the cog should change this to an A
           printf("load cogject into cog 7\n");
           load_cogject();
           sleep(1000);                                                  // delay while cog gets started
           c=peek(i);                                                    // peek byte at this location
           printf("Peek value at %i = character %c Ascii value %d \n",i,c,c);                            
           while (1);                                                     // Prop reboots on exit from main() so stop this
    }
    

    and the batch file to compile to xmm
    @echo off
    echo.
    echo    ===================
    echo    SETTING UP CATALINA
    echo    ===================
    echo.
    PATH=C:\Program Files\Catalina\bin;%PATH%
    Call catalina_env.bat()
    echo catalina -lcx -x5 -M 128k -D DRACBLADE -D HIRES_VGA COGTEST.C
    catalina -lcx -x5 -M 128k -D DRACBLADE -D HIRES_VGA COGTEST.C
    echo ***Make sure XMM.BINARY is copied from Utilities to Demos folder***
    echo Payload XMM COGTEST
    Payload XMM COGTEST
    

    and the batch file to create the cogject file
    @echo off
    echo.
    echo    ===================
    echo    SETTING UP CATALINA
    echo    ===================
    echo.
    PATH=C:\Program Files\Catalina\bin;%PATH%
    echo Call catalina_env.bat()
    Call catalina_env.bat()
    echo Erase previous files
    del cogject.binary
    del cogject.h
    del "c:\program files\catalina\include\cogject.h"
    echo homespun -b -d cogject.spin
    homespun -b -d cogject.spin
    echo spinc cogject.binary to cogject.h
    spinc cogject.binary >  cogject.h
    echo xcopy to the include folder
    xcopy cogject.h "c:\program files\catalina\include" /Y
    pause
    

    it is returning B, so the poke is working but the cog code to replace it with an A is not working.
  • kuronekokuroneko Posts: 3,623
    edited 2010-12-15 16:30
    It only does what you tell it to do. Namely fill cog register testvariable with #65 (thereby overwriting the 5000 stored in there). You want to affect hub RAM address 5000 so you should use hub access code.
    DAT             org     0
    
    cogstart        [B][COLOR="blue"]wrbyte[/COLOR][/B]  testvalue, testvariable ' test value A
                    jmp     #cogstart
    
    
    testvariable    long    5000                    ' test memory location 5000
    testvalue       long    65
    
                    fit
    
  • RossHRossH Posts: 5,580
    edited 2010-12-15 19:16
    Kuroneko ...

    Thanks!

    Dr_Acula ...

    I realize this is just an example, but as a demonstration it might be better to pass the address (5000) in the par block. For example:
    unsigned long par_cogject[] = { 5000 };                           // data to pass to cog
    
    [FONT=Arial]void load_cogject()
    {
           _coginit((int)par_cogject>>2, (int)cogject_array>>2, 7);      // load into cog 7
    }[/FONT]
    

    Then your PASM program might be:
    DAT             org     0
    
    cogstart        rdlong  testvariable, par
    cogloop         wrbyte  testvalue, testvariable ' test value A
                    jmp     #cogloop
    
    
    testvariable    long    0                       ' test memory location
    testvalue       long    65
    


    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-15 21:49
    Thanks kuroneko - well spotted.

    @Ross - not quite ready for your suggestion as the code still isn't doing what it is supposed to do. Looking forward to sending a variable, but first:
    CON
      _clkfreq = 80_000_000
      _clkmode = xtal1 + pll16x
    
    PUB Main
        coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value
    
    DAT
                      org 0
    cogstart          wrbyte  testvalue, testvariable ' test value A
                      jmp #cogstart
    
    testvariable      long    5000           ' test memory location 5000
    testvalue         long    65             ' ascii A
                      fit 496
    

    Just to double check, the .lst output is
    0000: 00 b4 c4 04 ' Frequency: 80000000 Hz
    0004: 6f          ' XTAL mode
    0005: 83          ' Checksum
    0006: 10 00       ' Base of program
    0008: 30 00       ' Base of variables
    000a: 38 00       ' Base of stack
    000c: 28 00       ' Initial program counter
    000e: 3c 00       ' Initial stack pointer
    
    '******************************************************************************
    '                                cogject.spin                                  
    '******************************************************************************
    
    '=================================== CONs =====================================
    _clkfreq = 80000000
    _clkmode = 1032
    '=============================== Object Header ================================
    0010: 20 00 02 00 ' 32 bytes, 2-1 methods, 0 object pointers
    0014: 18 00 00 00 ' ptr #1 to $0028: PUB Main (locals size: 0)
    '================================ DAT Section =================================
    0018(0000):             '                   org 0
    0018(0000): 02 06 3c 00 ' cogstart          wrbyte  testvalue, testvariable ' test value A
    001c(0001): 00 00 7c 5c '                   jmp #cogstart
    0020(0002): 88 13 00 00 ' testvariable      long    5000           ' test memory location 5000
    0024(0003): 41 00 00 00 ' testvalue         long    65             ' ascii A
    '============================ Method #1: PUB Main =============================
    'PUB Main
    '------------------------------------------------------------------------------
        coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value
    '------------------------------------------------------------------------------
    0028: 36             PUSH#1	
    0029: c7 08          PUSH#.L	OBJ+8
    002b: 35             PUSH#0	
    002c: 2c             COGISUB	
    002d: 32             RETURN	
    002e: 00 00       
    0030: ff ff f9 ff ff ff f9 ff 
    

    and the .h file is
    /** 
     * @file cogject_array.h
     * Created with spin.binary PASM to C Array Converter.
     * Copyright (c) 2010, John Doe
     */
    unsigned long cogject_array[] =
    {
        0x003c0602, 0x5c7c0000, 0x00001388, 0x00000041
    };
    
    

    Any help would be most appreciated.
  • RossHRossH Posts: 5,580
    edited 2010-12-16 00:22
    @Dr_Acula,

    Your main problem is that you are using the XMM LARGE (-x5) memory model, where data is in XMM RAM, not Hub RAM. This means your cogject_array is in XMM RAM, and therefore the coginit function can't load it - instead, it is loading some random rubbish from hub RAM.

    If you want to continue to use this memory model, you will need to copy the cogject_array to hub RAM before attempting to use it. The same is true of the par_cogject array. Since local variables are always in hub RAM, you should use code something like this:
    void load_cogject()
    {
          unsigned long hub_array[512];
          unsigned long par_cogject[] = { 1, 2, 3 };  // data to pass to cog - ignore if not used
          int i;
    
          for (i = 0; i < 512; i++) {
             hub_array[i] = cogject_array[i];
    
          }
          _coginit((int)par_cogject>>2, (int)hub_array>>2, 7);      // load into cog 7
           
    }
    
    Also, you are quite likely to be running out of cogs. Since you don't need the mouse, or the keyboard, or the floating point plugin, or the SD card plugin (all of which are being loaded for you) you should use a compile command more like the following:
    [FONT=Arial]catalina -lc -x5 -M 128k -D DRACBLADE -D HIRES_VGA -D NO_FP -D NO_MOUSE -D NO_KEYBOARD cogtest.c[/FONT]
    

    This works for me.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-16 01:15
    Ah - that would make sense. So I'll need to set aside a little bit of buffer space in hub for loading cogs? The same buffer space could be reused each time a cog is loaded.

    Looks like I need a generic routine based on your example to move data from array x to hub. And if we pass the location of an array, it could 'hide' the >> for the coginit like you mentioned earlier.

    In a general sense, all the catalina comms are in high memory, so maybe I could use a buffer from 0-512, (0-2 kilobytes) and then maybe 20k for video buffer, and that still should leave room for stack space (?10k)

    OR - I just noticed
    Since local variables are always in hub RAM
    . Where are they exactly - up the top of hub ram?

    Re the options without the mouse, the next thing I am going to do is try wiping out the cogs one at a time and then reloading them from the software. So I'll probably leave the default there for debugging. That might be a bit of a challenge, but it is a step along the way towards doing clever things like changing the VGA from text to color to grayscale from within software.
  • RossHRossH Posts: 5,580
    edited 2010-12-16 01:29
    Dr_Acula wrote: »
    Ah - that would make sense. So I'll need to set aside a little bit of buffer space in hub for loading cogs? The same buffer space could be reused each time a cog is loaded.

    Looks like I need a generic routine based on your example to move data from array x to hub. And if we pass the location of an array, it could 'hide' the >> for the coginit like you mentioned earlier.

    In a general sense, all the catalina comms are in high memory, so maybe I could use a buffer from 0-512, (0-2 kilobytes) and then maybe 20k for video buffer, and that still should leave room for stack space (?10k)
    .

    Just use a local array, as in my example. When you need it, it gets allocated automatically, and when you don't it doesn't consume any valuable hub space.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-16 01:34
    Crossed post there - I just reread your post and realised what you said. So - when I call a function, if I define an array in that function for say, 1000 bytes, does that array get stored in the hub (in the stack?) and then is deallocated when the function finishes?

    If so - does this mean the biggest array one could have in a local function is about 30k?
  • RossHRossH Posts: 5,580
    edited 2010-12-16 01:56
    Dr_Acula wrote: »
    Crossed post there - I just reread your post and realised what you said. So - when I call a function, if I define an array in that function for say, 1000 bytes, does that array get stored in the hub (in the stack?) and then is deallocated when the function finishes?

    If so - does this mean the biggest array one could have in a local function is about 30k?

    Yes, 32kb is the biggest you can have as a local variable under any Catalina memory model.

    If you need anything bigger than that you must use the XMM LARGE memory model and allocate the space you need on the heap (using malloc) - you can have megabytes of storage that way.

    This is one of the main differences between the XMM LARGE and XMM SMALL memory models - i.e. in the XMM LARGE (-x5) memory model the heap is in XMM RAM. In the XMM SMALL (-x2) memory model the heap is in HUB RAM.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-16 05:33
    Woot!

    It works! Prints "A".

    Isn't C just full of surprises. malloc for instance.

    But now I know how to load and reload cogs from within a program, I think this is going to open up a whole lot of new possibilities. First, the obvious one is that it frees up hub ram to do the one thing that I think hub ram does better than anything else, and that is to act as a video buffer. The second thing is to help solve the problem of never having quite enough cogs. For instance, you can load an SD driver cog, read the sd card with 100k of data, replace that driver with a serial port driver cog, and output the data. Or load some vga driver cogs and play a little movie with that 100k of data. Or play a wav file.

    Ok, next little task is to pass a variable and get it back. I need to go back and study the registry in more detail.

    Then I need to take a look at a typical Obex spin/pasm piece of code and think about how to turn this into a C/pasm piece of code. It probably will involve keeping the pasm largely as is, and turning the Spin into C. But it is the binding of the two that is the complicated part. From a vague top-down point of view, I think the idea is to take each Spin PUB function and translate to a C function, but keep links to the associated pasm code. So I think I'll be using the vb.net IDE and frequently swapping between the C and PASM tabs.

    BTW - if there is anyone out there who wants to be part of this, let us know as I can post the IDE code. I had a crazy idea on the way home from work that vb.net does lend itself to collaborative input on a program, in that you can create a program and create a tab frame and allow contributors to add a tab item to the frame, then they can add code and visual objects as much as they like and it would stay separate from the other code. eg I have some skeleton code for image manipulation as a separate tab, so if, hypothetically, someone wanted to add a tab for sound manipulation, they could contribute to the IDE without affecting other code.

    Just a thought, anyway. My little task here is to make things easier to use. eg - you can run the following code on a propeller by pressing F12
    /* Cog test program - see bottom of code for the Main function */
    
    #include <stdio.h>
    #include <cogject.h>
    
    void load_cogject()
    {
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++) 
           {
                  hub_array[i] = cogject_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, 7);          // load into cog 7
           
    }
    
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                  t_setpos(0,0,i);                                       // move cursor to next line */
                  t_color(0,0x08FC);                                     // RRGGBBxx eg dark blue background 00001000 white text 11111100 
           }
    }
    
    void stopcog(int cognumber)                                          // stop a cog
    {
           _cogstop(cognumber);
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void fill_memory(int start_address,int finish_address,char value)    // fill memory with these bytes
    {
           int i;
           for(i=start_address;i <= finish_address;i++)
           {
                  poke(i,value);   
           }
    }
    void main () 
    {
           char c;     
           int i;     
           clearscreen();
           printf("Hello, World!\n");
           printf("Clock speed %u \n",_clockfreq());                       // see page 28 of the propeller manual for other useful commands
           printf("Catalina running in cog number %i \n",_cogid());        // integer
           i=5000;                                                       // location to peek and poke
           poke(i,66);                                                   // poke a B, the cog should change this to an A
           printf("load cogject into cog 7\n");
           load_cogject();
           c=peek(i);                                                    // peek byte at this location
           printf("Peek value at %i = character %c Ascii value %d \n",i,c,c);                            
           while (1);                                                     // Prop reboots on exit from main() so stop this
    }
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-25 00:27
    I've had a little break away from this code and it has been good because I've been able to reflect on some cunning ways to write code. (I have updated my website - see link, for the latest board plus inbuilt links to Youtube and Paypal. Thanks ++ to http://viviti.com/ for making it easy to build an online store).

    Ok, this is the design challenge. I want to be able to write inline pasm code within a C program in the same way as the proptool. Now, Catalina in external memory can have inline pasm because it is running in LMM, but this isn't quite as useful as I'd like because the timing is not precise, it is not as fast as real cog code, and you can't set things running in the background.

    So I want some pasm code that I can load into a cog on the fly from within code. All fine, but for me personally, I want the entire program to be a single text file. RossH on the other hand has said he does not want me to create code that only my IDE can compile, and it is great he has said this because it makes a lot of sense.

    So - how do you put pasm code in a C program that will compile with Catalina and also with my IDE?

    The answer I have come up with is to put the pasm code within a comment block. So C treats it as a comment. But my IDE is able to find that code, preprocess it, shell out to SpinC to produce a .h file, then reinsert the compiled binary data into the program as a data statement for an array.

    So what you can do is use the IDE and compile/download/run the included cog code with a single press of F12.

    But you could also do a copy/paste of the pasm code, run it through spinc manually and then manually paste it back into the program, and so this would also run fine with any catalina compiler.

    I've also added some automatic color highlighting of the pasm code.

    There is also the ability to rebuild all the indents so they look neat (the code to do this is easier to write if { sits on a line by itself, so that is the reason I'm using the slightly more unusual C formatting of putting { on its own line.)

    Screenshot of what the code looks like is below. I'm adding various buttons so you can pre-write this code easily, eg this was written with one click of a button.
    1024 x 768 - 113K
  • RossHRossH Posts: 5,580
    edited 2010-12-25 18:33
    Dr_Acula wrote: »
    I've had a little break away from this code and it has been good because I've been able to reflect on some cunning ways to write code. (I have updated my website - see link, for the latest board plus inbuilt links to Youtube and Paypal. Thanks ++ to http://viviti.com/ for making it easy to build an online store).

    Ok, this is the design challenge. I want to be able to write inline pasm code within a C program in the same way as the proptool. Now, Catalina in external memory can have inline pasm because it is running in LMM, but this isn't quite as useful as I'd like because the timing is not precise, it is not as fast as real cog code, and you can't set things running in the background.

    So I want some pasm code that I can load into a cog on the fly from within code. All fine, but for me personally, I want the entire program to be a single text file. RossH on the other hand has said he does not want me to create code that only my IDE can compile, and it is great he has said this because it makes a lot of sense.

    So - how do you put pasm code in a C program that will compile with Catalina and also with my IDE?

    The answer I have come up with is to put the pasm code within a comment block. So C treats it as a comment. But my IDE is able to find that code, preprocess it, shell out to SpinC to produce a .h file, then reinsert the compiled binary data into the program as a data statement for an array.

    So what you can do is use the IDE and compile/download/run the included cog code with a single press of F12.

    But you could also do a copy/paste of the pasm code, run it through spinc manually and then manually paste it back into the program, and so this would also run fine with any catalina compiler.

    I've also added some automatic color highlighting of the pasm code.

    There is also the ability to rebuild all the indents so they look neat (the code to do this is easier to write if { sits on a line by itself, so that is the reason I'm using the slightly more unusual C formatting of putting { on its own line.)

    Screenshot of what the code looks like is below. I'm adding various buttons so you can pre-write this code easily, eg this was written with one click of a button.

    Hi Dr_Acula,

    This seems like a good solution - incluing the PASM that the C code relies on as a comment block makes it self-documenting. And being able to compile it with other tools means it is not tied to any specific toolset.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-26 05:27
    Great. I got the vb code working tonight. This can handle any number of included pasm code - just name each one a different name in the comment block eg
    PASM Start mycode.spin

    and 'mycode' becomes the name of the .h file as well as the unique name of the array in the C function.

    I've got a 'precompile' button on the IDE that rebuilds the code. Take the pasm code, create a .h file, remove the previous C function below the pasm code block and completely rebuild it with the new code.

    So easy to use - I changed the test letter from A to D, clicked the precompile button, then F12 to compile and download and it works.
        Private Sub CompileWithPASMCodeToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CompileWithPASMCodeToolStripMenuItem.Click
            ' convert all pasm code into data listings underneath the pasm code as a C function
            Dim i As Integer
            Dim NumberLines As Integer
            Dim PasmCode As Boolean
            Dim LineOfText As String
            Dim PasmString As String
            Dim PASMFilename As String
            Dim RemoveFlag As Boolean
            Dim TempString As String
            PasmCode = False ' not reading some pasm code
            NumberLines = RichTextBox1.Lines.Length
            'create all the cogs as .h files
            For i = 0 To NumberLines - 1
                LineOfText = RichTextBox1.Lines(i)
                ' order here is important - end first, then check, then start
                If Strings.Left(LineOfText, 8) = "PASM End" Then
                    TextBox16.Text = PASMFilename ' move over to the pasm tab
                    RichTextBox3.Text = PasmString ' move to the pasm richtextbox
                    CompilePause = False ' stop at end of shell - not writing file properly with no pause?!
                    System.Windows.Forms.Application.DoEvents() ' update the richtextbox
                    CompilePasm() ' compile it and save it
                    PasmCode = False ' finish logging
                    System.Windows.Forms.Application.DoEvents() ' update the richtextbox
                End If
                If PasmCode = True Then PasmString += LineOfText + vbCrLf
                If Strings.Left(LineOfText, 10) = "PASM Start" Then
                    TabControl1.SelectedIndex = 4 ' display the pasm code
                    System.Windows.Forms.Application.DoEvents() ' update the richtextbox
                    PasmCode = True ' start logging the data
                    PasmString = "" ' clear the string
                    PASMFilename = Strings.Mid(LineOfText, 12) ' filename stored after PASM Start
                End If
            Next i
            ' remove all the associated cog code underneath the pasm ie the next function
            ' use tempstring as a temp store
            RemoveFlag = False
            TempString = ""
            For i = 0 To NumberLines - 1
                LineOfText = RichTextBox1.Lines(i)
                If RemoveFlag = False Then TempString += LineOfText + vbCrLf
                If RemoveFlag = True And LineOfText = "}" Then RemoveFlag = False
                If Strings.Left(LineOfText, 8) = "PASM End" Then RemoveFlag = True
            Next
            RichTextBox1.Text = TempString ' put back the modified file
            NumberLines = RichTextBox1.Lines.Length ' shorter now so get new length
            TempString = ""
            For i = 0 To NumberLines - 1
                LineOfText = RichTextBox1.Lines(i)
                If Strings.Left(LineOfText, 10) = "PASM Start" Then
                    PASMFilename = Strings.Mid(LineOfText, 12) ' filename stored after PASM Start
                    PASMFilename = Strings.Left(PASMFilename, Strings.Len(PASMFilename) - 5) ' strip off the spin bit
                End If
                If Strings.Left(LineOfText, 8) = "PASM End" Then
                    ' add in the new code
                    TempString += "PASM End" + vbCrLf
                    TempString += "*/" + vbCrLf
                    TempString += vbCrLf
                    TempString += "void " + PASMFilename + "()                         // unique name for each loader" + vbCrLf
                    TempString += "{" + vbCrLf
                    ' add the .h file
                    FileOpen(1, "C:\Program Files\Catalina\Demos\" + PASMFilename + ".h", OpenMode.Input) ' open a file
                    Do
                        LineOfText = LineInput(1)
                        TempString += LineOfText + vbCrLf
                    Loop Until LineOfText = "};"
                    FileClose(1) ' close the .h file
                    TempString += "unsigned long hub_array[512];" + vbCrLf
                    TempString += "unsigned long par_cogject[] = { 1, 2, 3 };  // data to pass to cog - ignore if not used" + vbCrLf
                    TempString += "int i;" + vbCrLf
                    TempString += "for (i = 0; i < 512; i++)" + vbCrLf
                    TempString += "{" + vbCrLf
                    TempString += "hub_array[i] = " + PASMFilename + "_array[i];" + vbCrLf
                    TempString += "}" + vbCrLf
                    TempString += "_coginit((int)par_cogject>>2, (int)hub_array>>2, 7);      // load into cog 7" + vbCrLf
                    TempString += "}" + vbCrLf
                Else
                    TempString += LineOfText + vbCrLf ' add line to tempstring
                End If
            Next i
            RichTextBox1.Text = TempString ' put back modified file
            Indents() ' add the proper indentation
            ColorCatalina() ' display in color
            TabControl1.SelectedIndex = 0 ' display the c code
        End Sub
    

    Ok, now on to something more complicated. The whole point of all this is to make it much easier to translate Spin objects into Catalina objects. Using the above it is now possible to write lots of C functions that copy the Spin functions, and then hopefully copy and paste the PASM in directly.

    The hard part is binding the two together. I'm going to try this with some real code and see what happens. It may be that the registry is enough and you can pass the location of a block of hub ram.

    The hard sort of code is where the Pasm part of an existing spin object is talking to a block of hub ram. It might be an array, or worse, it might be a number of variables that on the spin compiler end up scattered all over hub ram. The spin compiler does not care, as the pasm object code knows where the variables ended up.

    I'm thinking of how this fits with the registry model. Say existing spin code has pasm that is talking to 100 bytes of hub ram. At the very least, if those are not contiguous you would rewrite the code so that it is. But even after doing this, we need a way to say that these 100 bytes of ram are reserved and I am not sure how to do that with the registry.

    Say object 1 reserves 100 bytes and object 2 reserves 10 and object 3 reserves 4. We don't want each one to overwrite the other. And it would help to have the flexibility to add more code.

    I am wondering about using constants in the C code and linking the C functions using those constants. And also passing those constants to the pasm comment blocks.

    I guess there will never be a perfect solution if many cogs are being loaded and reloaded. As an example, say one is loading cogs to drive text graphics, then to drive color graphics. Color might reserve 19200 bytes of hub ram. Text would be 3200. So one might say that color graphics are bigger than text, so then put the keyboard circular buffer above 19200. One could be loading in a variety of display drivers/tile drivers etc, but as long as they are never more than 19200 then things would be ok.

    Mostly this is something that C contains within itself, but sometimes changing something might need to get passed to pasm as well. So any constant definitions in C might be at the beginning, and maybe the pasm preprocessor looks for these and modifies pasm code accordingly?

    To put it another way, maybe the whole hub memory map is defined with constants at the beginning of the C program?

    I guess I'll need to have a go at translating an existing object to get a feel for how this might work.

    Addit: Brainwave this morning in the shower. At the beginning of the C program, define a list of constants that show what the memory map should be eg
    2048 for cog loading
    19200 for graphics buffer
    50 for keyboard buffer
    128 for serial port buffer

    C knows about this as these are const definitions
    PASM can be told about it as the preprocessor can copy this list of constants into every bit of PASM code into the CON section, and translate from C syntax to pasm syntax.

    This becomes the glue between pasm and C

    This will make translating existing object code to C a lot easier.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-28 01:05
    A question for RossH,

    In the code below I'm starting to define constants at the beginning of the C program that define how hub memory is to be used.

    I am still a little confused about loading cogs. I'd like to reserve hub memory locations 0 to 2047 for loading cogs.

    In this code, how does unsigned long hub_array[512]; know where it should end up?

    Does it end up at location 0 or some other location in hub?

    Help here would be most appreciated!


    Below is some code that glues together C and PASM. Hit Shift F12 and it compiles/downloads/runs on a propeller. But there are some subtleties here:
    1) constants defined at the beginning of the C program are translated to CON and copied to every example of PASM code.
    2) The precompiler takes all PASM code and converts it to C and copies it back into the C program by reading back the .h program that has been created.
    3) at the bottom of the screenshot is a line "testvariable long graphicstart". This shows an example of gluing C and PASM together. At the bottom of the code text is how this is used in C.
    i=graphicstart; // location to peek and poke

    So - this is still a standard C program. It will compile with catalina.

    But- change a constant at the beginning of the C program and recompile and all the PASM gets updated too.

    If you want to share variables, use a constant hub location as both C and PASM will know where it is.

    And yes, I know this bypasses the registry system. Why am I doing that? Well, I am worried about existing PASM objects that have no code space free at all. This system means that such code should drop into Catalina objects with no need to add any registry interface code.

    I think I am now getting close to attempting to port spin objects over to C.
    /* PASM demo for use with Catalina Precompiler/Compiler */
    
    #include <stdio.h>
    
    /* Hub memory map and other constants used by PASM routines */
    const unsigned long int cogload       = 0;                           // start of space for loading cogs 2048 bytes= 496 longs
    const unsigned long int cogloadsize   = 2048;                        // size of cogload space
    const unsigned long int graphicstart  = 2048;                        // start of space for video graphics buffer
    const unsigned long int graphicsize   = 19200;                       // size of graphics buffer = 19200 bytes
    const unsigned long int keyboardstart = 21248;                       // start of space for keyboard
    const unsigned long int keyboardsize  = 100;                         // size of space for keyboard
    const unsigned long int cogjectstart  = 21348;                       // start of space for mycogject
    const unsigned long int cogjectsize   = 1;                           // size of space for mycogject
    /* End hub memory map */
    
    /* PASM Code for compilation using SpinC and inclusion as a data file
    PASM Start mycogject.spin
    CON
      _clkfreq = 80_000_000                                              ' 5Mhz Crystal
      _clkmode = xtal1 + pll16x                                          ' x 16
                                                                         ' Start of C hub memory map constants
      cogload       = 0
      cogloadsize   = 2048
      graphicstart  = 2048
      graphicsize   = 19200
      keyboardstart = 21248
      keyboardsize  = 100
      cogjectstart  = 21348
      cogjectsize   = 1
                                                                         ' End of C constants
    
    PUB Main
        coginit(1,@cogstart,0)                                           ' cog 1, cogstart, dummy value
    
    DAT
                      org 0
    cogstart          wrbyte  testvalue, testvariable                    ' test value A
                      jmp #cogstart
    
    testvariable      long    graphicstart                               ' test memory location at graphicstart
    testvalue         long    65                                         ' ascii A
                      fit     496
    PASM End
    */
    
    void mycogject()                                                     // unique name for each loader
    {
           /** 
            * @file mycogject_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2010, John Doe
            */
           unsigned long mycogject_array[] =
           {
               0x003c0602, 0x5c7c0000, 0x00000800, 0x00000041
           };
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++)
           {
                  hub_array[i] = mycogject_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, 7);          // load into cog 7
    }
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                   t_setpos(0,0,i);                                      // move cursor to next line
                   t_color(0,0x08FC);                                    // RRGGBBxx eg dark blue background 00001000 white text 11111100
           }
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void main ()
    {
           char c;
           int i;
           clearscreen();
           printf("Clock speed %u \n",_clockfreq());                     // see page 28 of the propeller manual for other useful commands
           printf("Catalina running in cog number %i \n",_cogid());      // integer
           i=graphicstart;                                               // location to peek and poke
           poke(i,66);                                                   // poke a B, the cog should change this to an A
           printf("load cogject into cog 7\n");
           mycogject();
           c=peek(i);                                                    // peek byte at this location
           printf("Peek value at %i = character %c Ascii value %d \n",i,c,c);
           while (1); // Prop reboots on exit from main()
    }
    
    1024 x 768 - 142K
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-30 16:00
    Learning a lot as we go. Re the question above, I think the cogs are loaded from within the stack space at the top of hub ram, so I think I can start using hub ram from location 0 instead of location 2048.

    These are some notes to myself as I port Kye's video driver over to C. Some of these will be obvious to those experienced with C and Spin.

    1) in the dummy PUB that has coginit, the value in cogint that starts with an @ should match with the first line in the DAT section that comes after the org 0.

    2) Kye's code uses some calculations to work out values based on pins and frequency, including some spin code that does a 64 by 32 bit divide. For pin group 2, the constants work out as
    directionstate_const = $00FF0000 ' for pin group 2
    videostate_const = $30_00_04_FF ' for pin group 2
    frequencystate_const = 337914606 ' calculated for 80Mhz

    3) For constants just used locally in PASM, define them in the CON section above the _clkfreq line. The precompiler uses the line _clkmode as a flag and copies the C constants after this line, so this is where common constants go that are used by both C and PASM.

    4) For passing longs between C and PASM, define a memory location in the global constants part of C. Then use wrlong and rdlong in pasm, and peek and poke in C to pass data back and forth.

    5) I keep forgetting what I learned about PASM and again I've found out through various syntax errors that PASM is a hybrid 32 bit/ 9 bit language. So to help my flagging neurons fix this in memory, you can't use constants in pasm code. mov myvariable,myconstant will not work. Instead, near the bottom of the code, define a new value with myvalue long myconstant, then in the code, mov myvariable,myvalue

    6) Passing values between Spin and PASM is not the same as between C and PASM. A typical example of some spin code is to do some maths on a long in a supporting PUB. Where is this long first defined? Not as a | in the PUB and not as a global variable in the Spin code. This long is defined usually at the bottom of the PASM code as 'myvariable long 0'. This is a special sort of long and the only way to find these is to do ^F on the name of the longs, scroll through the PASM code where they will usually be mentioned several times, then find that they are defined in PASM code. The proptool compiles this code and 'myvariable' ends up in a hub location that happens to be in the middle of some PASM code that is going to be loaded into a cog. When the PUB Start is run to start this cog, a value might be calculated for myvariable, the value gets stored in hub ram at the location that ends up part of cog code, and then when the cog is started, this value is ready for the cog to use.

    We can't do this in C!

    The precompiler can glue together constants easily but these 'PASM defined' variables are more complex to handle, especially with self contained cogjects that are going to be loaded in and out multiple times. We can cheat and turn some into constants and then define them in the PASM code as "myvariable long myconstant". But for others, I can't see any solution apart from calculating them in C, storing them to fixed hub locations that are defined in the global constants section using poke, then using a wrlong in PASM to read them back.

    Or use the registry?

    So - in general, when translating to C, look in the PUB start of the existing object. Any variables that seem to be passed with @ symbols will need known global locations defined in hub ram. Any variables that seem to end up in the PASM code as well - either try to convert these to constants, or if not, then also define a hub ram location for each, and use a rdlong in PASM.

    I have yet to look at code in other supporting PUBs but I suspect there will be more of these 'longs that are defined in pasm code and used in Spin'. I guess all the variables will end up as a group which might make the code easier to read. It also would be a step towards reloadable spin objects as these are currently not possible for most objects due to the way code is glued together.
    {{
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // VGA64 6 Bits Per Pixel Engine
    //
    // Author: Kwabena W. Agyeman
    // Updated: 11/17/2010
    // Designed For: P8X32A
    // Version: 1.0
    //
    // Copyright (c) 2010 Kwabena W. Agyeman
    // See end of file for terms of use.
    //
    // Update History:
    //
    // v1.0 - Original release - 11/17/2009.
    //
    // For each included copy of this object only one spin interpreter should access it at a time.
    //
    // Nyamekye,
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Video Circuit:
    //
    //     0   1   2   3 Pin Group
    //
    //                     240OHM
    // Pin 0,  8, 16, 24 ----R-------- Vertical Sync
    //
    //                     240OHM
    // Pin 1,  9, 17, 25 ----R-------- Horizontal Sync
    //
    //                     470OHM
    // Pin 2, 10, 18, 26 ----R-------- Blue Video
    //                            |
    //                     240OHM |
    // Pin 3, 11, 19, 27 ----R-----
    //
    //                     470OHM
    // Pin 4, 12, 20, 28 ----R-------- Green Video
    //                            |
    //                     240OHM |
    // Pin 5, 13, 21, 29 ----R-----
    //
    //                     470OHM
    // Pin 6, 14, 22, 30 ----R-------- Red Video
    //                            |
    //                     240OHM |
    // Pin 7, 15, 23, 31 ----R-----
    //
    //                            5V
    //                            |
    //                            --- 5V
    //
    //                            --- Vertical Sync Ground
    //                            |
    //                           GND
    //
    //                            --- Hoirzontal Sync Ground
    //                            |
    //                           GND
    //
    //                            --- Blue Return
    //                            |
    //                           GND
    //
    //                            --- Green Return
    //                            |
    //                           GND
    //
    //                            --- Red Return
    //                            |
    //                           GND
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
    CON
    
      #$FC, Light_Grey, #$A8, Grey, #$54, Dark_Grey
      #$C0, Light_Red, #$80, Red, #$40, Dark_Red
      #$30, Light_Green, #$20, Green, #$10, Dark_Green
      #$0C, Light_Blue, #$08, Blue, #$04, Dark_Blue
      #$F0, Light_Orange, #$A0, Orange, #$50, Dark_Orange
      #$CC, Light_Purple, #$88, Purple, #$44, Dark_Purple
      #$3C, Light_Teal, #$28, Teal, #$14, Dark_Teal
      #$FF, White, #$00, Black
    
    PUB plotBox(color, xPixelStart, yPixelStart, xPixelEnd, yPixelEnd) '' 8 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Plots a one color box of pixels on screen.
    '' //
    '' // Color - The color of the box of pixels to display on screen. A color byte (%RR_GG_BB_xx).
    '' // XPixelStart - The X cartesian pixel start coordinate. X between 0 and 159. Y between 0 and 119.
    '' // YPixelStart - The Y cartesian pixel start coordinate. Note that this axis is inverted like on all other graphics drivers.
    '' // XPixelEnd - The X cartesian pixel end coordinate. X between 0 and 159. Y between 0 and 119.
    '' // YPixelEnd - The Y cartesian pixel end coordinate. Note that this axis is inverted like on all other graphics drivers.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      xPixelEnd := ((xPixelEnd <# 159) #> 0)
      yPixelEnd := (((yPixelEnd <# 119) #> 0) * 160)
      xPixelStart := ((xPixelStart <# xPixelEnd) #> 0)
      yPixelStart := (((yPixelStart * 160) <# yPixelEnd) #> 0)
    
      yPixelEnd += xPixelStart
      yPixelStart += xPixelStart
      xPixelEnd -= --xPixelStart
    
      repeat result from yPixelStart to yPixelEnd step 160
        bytefill(@displayBuffer + result, (color | $3), xPixelEnd)
    
    PUB plotPixel(color, xPixel, yPixel) '' 6 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Plots a one color pixel on screen.
    '' //
    '' // Color - The color of the pixel to display on screen. A color byte (%RR_GG_BB_xx).
    '' // XPixel - The X cartesian pixel coordinate. X between 0 and 159. Y between 0 and 119.
    '' // YPixel - The Y cartesian pixel coordinate. Note that this axis is inverted like on all other graphics drivers.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      displayBuffer.byte[((xPixel <# 159) #> 0) + (160 * ((yPixel <# 119) #> 0))] := (color | $3)
    
    PUB displayClear '' 3 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Clears the screen to black.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      longfill(@displayBuffer, 0, constant((160 * 120) / 4))
    
    PUB displayPointer '' 3 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns a pointer to the display buffer.
    '' //
    '' // The display buffer is an array of 160 by 120 bytes. Each byte represents a pixel on the screen.
    '' //
    '' // Each pixel is a color byte (%RR_GG_BB_xx). Where RR, GG, and BB are the two bit values of red, green, blue respectively.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      return @displayBuffer
    
    PUB displayState(state) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Enables or disables the PIX Driver's video output - turning the monitor off or putting it into standby mode.
    '' //
    '' // State - True for active and false for inactive.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      displayIndicator := state
    
    PUB displayRate(rate) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns true or false depending on the time elasped according to a specified rate.
    '' //
    '' // Rate - A display rate to return at. 0=0.234375Hz, 1=0.46875Hz, 2=0.9375Hz, 3=1.875Hz, 4=3.75Hz, 5=7.5Hz, 6=15Hz, 7=30Hz.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      result or= (($80 >> ((rate <# 7) #> 0)) & syncIndicator)
    
    PUB displayWait(frames) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Waits for the display vertical refresh.
    '' //
    '' // The best time to draw on screen for flicker free operation is right after this function returns.
    '' //
    '' // Frames - Number of vertical refresh frames to wait for.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat (frames #> 0)
        result := syncIndicator
        repeat until(result <> syncIndicator)
    
    PUB displayColor(redAmount, greenAmount, blueAmount) '' 6 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Builds a color byte (%RR_GG_BB_xx) from red, green, and blue componets.
    '' //
    '' // RedAmount - The amount of red to add to the color byte. Between 0 and 3.
    '' // GreenAmount - The amount of green to add to the color byte. Between 0 and 3.
    '' // BlueAmount - The amount of blue to add to the color byte. Between 0 and 3.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      return ((((redAmount <# 3) #> 0) << 6) | (((greenAmount <# 3) #> 0) << 4) | (((blueAmount <# 3) #> 0) << 2) | $3)
    
    PUB PIXEngineStart(pinGroup) '' 7 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Starts up the PIX driver running on a cog.
    '' //
    '' // Returns true on success and false on failure.
    '' //
    '' // PinGroup - Pin group to use to drive the video circuit. Between 0 and 3.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      PIXEngineStop
      if(chipver == 1)
    
        pinGroup := ((pinGroup <# 3) #> 0)
        directionState := ($FF << (8 * pinGroup))
        videoState := ($30_00_00_FF | (pinGroup << 9))
    
        pinGroup := constant((25_175_000 + 1_600) / 4)
        frequencyState := 1
    
        repeat 32
          pinGroup <<= 1
          frequencyState <-= 1
          if(pinGroup => clkfreq)
            pinGroup -= clkfreq
            frequencyState += 1
    
        displayIndicatorAddress := @displayIndicator
        syncIndicatorAddress := @syncIndicator
        cogNumber := cognew(@initialization, @displayBuffer)
        result or= ++cogNumber
    
    PUB PIXEngineStop '' 3 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Shuts down the PIX driver running on a cog.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      if(cogNumber)
        cogstop(-1 + cogNumber~)
    
    DAT
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       PIX Driver
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            org     0
    
    ' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
    
    initialization          mov     vcfg,           videoState                 ' Setup video hardware.
                            mov     frqa,           frequencyState             '
                            movi    ctra,           #%0_00001_101              '
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Active Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    loop                    mov     displayCounter, par                        ' Set/Reset tiles fill counter.
                            mov     tilesCounter,   #120                       '
    
    tilesDisplay            mov     tileCounter,    #4                         ' Set/Reset tile fill counter.
    
    tileDisplay             mov     vscl,           visibleScale               ' Set/Reset the video scale.
                            mov     counter,        #40                        '
    
    ' //////////////////////Visible Video//////////////////////////////////////////////////////////////////////////////////////////
    
    videoLoop               rdlong  buffer,         displayCounter             ' Download new pixels.
                            add     displayCounter, #4                         '
    
                            or      buffer,         HVSyncColors               ' Update display scanline.
                            waitvid buffer,         #%%3210                    '
    
                            djnz    counter,        #videoLoop                 ' Repeat.
    
    ' //////////////////////Invisible Video////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     vscl,           invisibleScale             ' Set/Reset the video scale.
    
                            waitvid HSyncColors,    syncPixels                 ' Horizontal Sync.
    
    ' //////////////////////Repeat/////////////////////////////////////////////////////////////////////////////////////////////////
    
                            sub     displayCounter, #160                       ' Repeat.
                            djnz    tileCounter,    #tileDisplay               '
    
                            add     displayCounter, #160                       ' Repeat.
                            djnz    tilesCounter,   #tilesDisplay              '
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Inactive Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            add     refreshCounter, #1                         ' Update sync indicator.
                            wrbyte  refreshCounter, syncIndicatorAddress       '
    
    ' //////////////////////Front Porch////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #11                        ' Set loop counter.
    
    frontPorch              mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid HSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Horizontal Sync.
                            waitvid HSyncColors,    syncPixels                 '
    
                            djnz    counter,        #frontPorch                ' Repeat # times.
    
    ' //////////////////////Vertical Sync//////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #(2 + 2)                   ' Set loop counter.
    
    verticalSync            mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid VSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Vertical Sync.
                            waitvid VSyncColors,    syncPixels                 '
    
                            djnz    counter,        #verticalSync              ' Repeat # times.
    
    ' //////////////////////Back Porch/////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #31                        ' Set loop counter.
    
    backPorch               mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid HSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Horizontal Sync.
                            waitvid HSyncColors,    syncPixels                 '
    
                            djnz    counter,        #backPorch                 ' Repeat # times.
    
    ' //////////////////////Update Display Settings////////////////////////////////////////////////////////////////////////////////
    
                            rdbyte  buffer,         displayIndicatorAddress wz ' Update display settings.
                            muxnz   dira,           directionState             '
    
    ' //////////////////////Loop///////////////////////////////////////////////////////////////////////////////////////////////////
    
                            jmp     #loop                                      ' Loop.
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Data
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    invisibleScale          long    (16 << 12) + 160                           ' Scaling for inactive video.
    visibleScale            long    (4 << 12) + 16                             ' Scaling for active video.
    blankPixels             long    640                                        ' Blank scanline pixel length.
    syncPixels              long    $00_00_3F_FC                               ' F-porch, h-sync, and b-porch.
    HSyncColors             long    $01_03_01_03                               ' Horizontal sync color mask.
    VSyncColors             long    $00_02_00_02                               ' Vertical sync color mask.
    HVSyncColors            long    $03_03_03_03                               ' Horizontal and vertical sync colors.
    
    ' //////////////////////Configuration Settings/////////////////////////////////////////////////////////////////////////////////
    
    directionState          long    0
    videoState              long    0
    frequencyState          long    0
    
    ' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
    
    displayIndicatorAddress long    0
    syncIndicatorAddress    long    0
    
    ' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
    
    counter                 res     1
    buffer                  res     1
    
    tileCounter             res     1
    tilesCounter            res     1
    
    refreshCounter          res     1
    displayCounter          res     1
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            fit     496
    
    DAT
    
    ' //////////////////////Variable Arrary////////////////////////////////////////////////////////////////////////////////////////
    
    displayBuffer           long    0[(160 * 120) / 4]                         ' Display buffer.
    displayIndicator        byte    1                                          ' Video output control.
    syncIndicator           byte    0                                          ' Video update control.
    cogNumber               byte    0                                          ' Cog ID.
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    {{
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                  TERMS OF USE: MIT License
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    // Software is furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    // Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-12-30 19:03
    Success!

    Load up a catalina program, then load a video driver into a cog and change from a white on blue text screen to a graphics screen using Kye's 64 color 160x120 video driver.

    Compilation and download is simply Shift F12.

    If we can port one object into C, then other objects should be possible too. Next I need to see if I can load a text driver back in. Then a different SD card driver. Serial port drivers etc etc.

    This is a new way of using the propeller. 512k of memory. And never run out of cogs - just keep recycling them. You could put the whole Obex on an SD card and load them in and out as needed.

    I've attached the vb.net IDE. This is very messy code and some things like the auto indenting and color text are much slower than I would like. You can see some of the complexities of the precompiler where it goes through and removes old code, then creates new code and rebuilds the program prior to sending it off to spinc and catalina and homespun. The aim here is to make it easy for the coder - change one line of text and hit Shift F12 to test it.
    /* PASM demo for use with Catalina IDE Precompiler and Compiler */
    
    #include <stdio.h>
    
    /* Global constants for both C and PASM */
    const unsigned long int graphicstart  = 0;                           // start of space for video graphics buffer
    const unsigned long int displayindicator_const = 19200;                    // used by the graphics code change to 19200 when works
    const unsigned long int syncindicator_const = 19201;                       // used by the graphics code
    
    /* End global constants */
    
    /* PASM Code for compilation using SpinC and inclusion as a data file
    PASM Start vga160.spin
    CON
      directionstate_const = $00FF0000                                         ' for pin group 2                                                                        
      videostate_const = $30_00_04_FF                                          ' for pin group 2
      frequencystate_const = 337914606                                         ' calculated for 80Mhz
      _clkfreq = 80_000_000                                              ' 5Mhz Crystal
      _clkmode = xtal1 + pll16x                                          ' x 16
                                                                         ' Start of C hub constants
      graphicstart  = 0
      displayindicator_const = 19200
      syncindicator_const = 19201
                                                                         ' End of C constants
    
    PUB Main
        coginit(1,@initialization,0)                                           ' cog 1 dummy, cogstart, dummy value see Loop replaced par with #0
    
    DAT
    
                            org     0
    
    initialization          mov     vcfg,           videoState                 ' Setup video hardware.
                            mov     frqa,           frequencyState             '
                            movi    ctra,           #%0_00001_101              '
                            mov     displayindicatoraddress,  #1               ' startup value
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Active Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    loop                    mov     displayCounter, #graphicstart              ' buffer starts at hub ram zero must be < 9 bits value ie <512 so 0 is the logical choice                                                       
                            mov     tilesCounter,   #120                       '
    
    tilesDisplay            mov     tileCounter,    #4                         ' Set/Reset tile fill counter.
    
    tileDisplay             mov     vscl,           visibleScale               ' Set/Reset the video scale.
                            mov     counter,        #40                        '
    
    ' //////////////////////Visible Video//////////////////////////////////////////////////////////////////////////////////////////
    
    videoLoop               rdlong  buffer,         displayCounter             ' Download new pixels.
                            add     displayCounter, #4                         '
    
                            or      buffer,         HVSyncColors               ' Update display scanline.
                            waitvid buffer,         #%%3210                    '
    
                            djnz    counter,        #videoLoop                 ' Repeat.
    
    ' //////////////////////Invisible Video////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     vscl,           invisibleScale             ' Set/Reset the video scale.
    
                            waitvid HSyncColors,    syncPixels                 ' Horizontal Sync.
    
    ' //////////////////////Repeat/////////////////////////////////////////////////////////////////////////////////////////////////
    
                            sub     displayCounter, #160                       ' Repeat.
                            djnz    tileCounter,    #tileDisplay               '
    
                            add     displayCounter, #160                       ' Repeat.
                            djnz    tilesCounter,   #tilesDisplay              '
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Inactive Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            add     refreshCounter, #1                         ' Update sync indicator.
                            wrbyte  refreshCounter, syncIndicatorAddress       '
    
    ' //////////////////////Front Porch////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #11                        ' Set loop counter.
    
    frontPorch              mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid HSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Horizontal Sync.
                            waitvid HSyncColors,    syncPixels                 '
    
                            djnz    counter,        #frontPorch                ' Repeat # times.
    
    ' //////////////////////Vertical Sync//////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #(2 + 2)                   ' Set loop counter.
    
    verticalSync            mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid VSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Vertical Sync.
                            waitvid VSyncColors,    syncPixels                 '
    
                            djnz    counter,        #verticalSync              ' Repeat # times.
    
    ' //////////////////////Back Porch/////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #31                        ' Set loop counter.
    
    backPorch               mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid HSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Horizontal Sync.
                            waitvid HSyncColors,    syncPixels                 '
    
                            djnz    counter,        #backPorch                 ' Repeat # times.
    
    ' //////////////////////Update Display Settings////////////////////////////////////////////////////////////////////////////////
    
                            rdbyte  buffer,         displayIndicatorAddress wz ' Update display settings.
                            muxnz   dira,           directionState             '
    
    ' //////////////////////Loop///////////////////////////////////////////////////////////////////////////////////////////////////
    
                            jmp     #loop                                      ' Loop.
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Data
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    invisibleScale          long    (16 << 12) + 160                           ' Scaling for inactive video.
    visibleScale            long    (4 << 12) + 16                             ' Scaling for active video.
    blankPixels             long    640                                        ' Blank scanline pixel length.
    syncPixels              long    $00_00_3F_FC                               ' F-porch, h-sync, and b-porch.
    HSyncColors             long    $01_03_01_03                               ' Horizontal sync color mask.
    VSyncColors             long    $00_02_00_02                               ' Vertical sync color mask.
    HVSyncColors            long    $03_03_03_03                               ' Horizontal and vertical sync colors.
    
    
    ' //////////////////////Configuration Settings//////////////////////////////////////////
    
    directionState          long    directionstate_const
    videoState              long    videostate_const
    frequencyState          long    frequencystate_const
    
    ' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
    
    displayIndicatorAddress long    displayindicator_const                                
    syncIndicatorAddress    long    syncindicator_const    ' global constant                            
    
    ' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
    
    counter                 res     1
    buffer                  res     1
    
    tileCounter             res     1
    tilesCounter            res     1
    
    refreshCounter          res     1
    displayCounter          res     1
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            fit     496
    PASM End
    */
    
    void vga160()                                                     // unique name for each loader
    {
           /** 
            * @file vga160_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2010, John Doe
            */
           unsigned long vga160_array[] =
           {
               0xa0bffc33, 0xa0bff434, 0x58fff00d, 0xa0fc6a01, 
               0xa0fc7800, 0xa0fc7478, 0xa0fc7204, 0xa0bffe2c, 
               0xa0fc6e28, 0x08bc703c, 0x80fc7804, 0x68bc7031, 
               0xfc7c70e4, 0xe4fc6e09, 0xa0bffe2b, 0xfc3c5e2e, 
               0x84fc78a0, 0xe4fc7207, 0x80fc78a0, 0xe4fc7406, 
               0x80fc7601, 0x003c7636, 0xa0fc6e0b, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e17, 
               0xa0fc6e04, 0xa0bffe2d, 0xfc7c6000, 0xa0bffe2b, 
               0xfc3c602e, 0xe4fc6e1d, 0xa0fc6e1f, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e23, 
               0x02bc7035, 0x7cbfec32, 0x5c7c0004, 0x000100a0, 
               0x00004010, 0x00000280, 0x00003ffc, 0x01030103, 
               0x00020002, 0x03030303, 0x00ff0000, 0x300004ff, 
               0x14242aee, 0x00004b00, 0x00004b01
           };
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++)
           {
                  hub_array[i] = vga160_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, 7);          // load into cog 7
    }
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                   t_setpos(0,0,i);                                      // move cursor to next line
                   t_color(0,0x08FC);                                    // RRGGBBxx eg dark blue background 00001000 white text 11111100
           }
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void main ()
    {
    	int i;
    	clearscreen();
           printf("Clock speed %u \n",_clockfreq());                     // see page 28 of the propeller manual for other useful commands
           printf("load cogject into cog 7\n");
           printf("Catalina running in cog number %i \n",_cogid());      // integer
    	sleep(3000); // for display to warm up
    	for(i=0;i<500;i++)
    		{
    			poke(i,0x53); // fill some bytes with gold 0x53
    		}
           vga160();                                                     // start graphic driver in cog 7
    	_cogstop(6);	// shut down other cogs but not the one in _cogid above ie the C one
    	_cogstop(5);
    	_cogstop(4);
    	_cogstop(3);
    	_cogstop(0);
    	_cogstop(1);
    //	_cogstop(2);  // this cog is running C
    	poke(0,0xff); // white square
           while (1);                                                    // Prop reboots on exit from main()
    }
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-03 19:29
    Hi Ross,

    I'm making a lot of progress with translating Spin objects into C. I was wondering if I could ask your sage advice on where things get stored?
    /* PASM demo for use with Catalina IDE Precompiler and Compiler using XMM external memory, board http://smarthome.viviti.com/propeller
    C code by Dr_Acula (James Moxham)
    Catalina C compiler by RossH
    Individual cog code authors acknowledged in the code below.
     see post #493 http://forums.parallax.com/showthread.php?116370-Catalina-2.6-a-FREE-C-compiler-for-the-Propeller-The-Final-Frontier!/page25
    for some discussion about hub vs xmm memory. I need to 1) make sure the stack is not being filled up with all this cog code and
    2) need a way of passing parameters via par. (possibly via a common entry point in hub and a pointer passed to the load function)
    and 3) check where the Tweety array is ending up being stored.
    
    Code:
    
    int myarray_1[5000]; <-- in the LARGE XMM model, this will be in XMM RAM (global, file scope)
    
    int main() {
       int myarray_2[5000]; <-- this will always be in Hub RAM (on the stack, local scope)
       int *my_array_3 = malloc(5000); <-- in the LARGE XMM model, this will be in XMM RAM
    }
    
    Here is a reference you can look up on file scope. This is important in Catalina, since plugins can generally only access Hub RAM (i.e. they do not have access to XMM RAM) - this means that all variables used to communicate with plugins must be in Hub RAM. When using XMM, this can be done by making such variables "local" to the main function (and passing a pointer to them to anything outside that scope - when you see the new graphics plugin you'll see a working example of this
    */
    
    #include <stdio.h>
    
    /* Global constants for both C and PASM */
    const unsigned long int graphicstart  = 100;                               // start of space for video graphics buffer - problems if less than 100 but must be under 512
    const unsigned long int displayindicator_const = 19998;                    // 19200 plus a buffer (tile drivers might use more)
    const unsigned long int syncindicator_const = 19999;                       // used by the graphics code
    /* End global constants */
    
    /* PASM Code for compilation using SpinC and inclusion as a data file
    
    VGA64 6 Bits Per Pixel Engine
    
    Author: Kwabena W. Agyeman
    Updated: 11/17/2010
     Designed For: P8X32A
    Version: 1.0
    
    Copyright (c) 2010 Kwabena W. Agyeman
    See end of file for terms of use.
    
    Update History:
    
    v1.0 - Original release - 11/17/2009.
    
    PASM Start vga160.spin
    CON
      directionstate_const = $00FF0000                                         ' for pin group 2                                                                        
      videostate_const = $30_00_04_FF                                          ' for pin group 2
      frequencystate_const = 337914606                                         ' calculated for 80Mhz
      _clkfreq = 80_000_000                                              ' 5Mhz Crystal
      _clkmode = xtal1 + pll16x                                          ' x 16
                                                                         ' Start of C hub constants
      graphicstart  = 100
      displayindicator_const = 19998
      syncindicator_const = 19999
                                                                         ' End of C constants
    
    PUB Main
        coginit(1,@initialization,0)                                           ' cog 1 dummy, cogstart, dummy value see Loop replaced par with #0
    
    DAT
    
                            org     0
    
    initialization          mov     vcfg,           videoState                 ' Setup video hardware.
                            mov     frqa,           frequencyState             '
                            movi    ctra,           #%0_00001_101              '
                            mov     displayindicatoraddress,  #1               ' startup value
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Active Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    loop                    mov     displayCounter, #graphicstart              ' buffer starts at graphicstart must be < 9 bits value ie <512 so 0 is the logical choice                                                       
                            mov     tilesCounter,   #120                       '
    
    tilesDisplay            mov     tileCounter,    #4                         ' Set/Reset tile fill counter.
    
    tileDisplay             mov     vscl,           visibleScale               ' Set/Reset the video scale.
                            mov     counter,        #40                        '
    
    ' //////////////////////Visible Video//////////////////////////////////////////////////////////////////////////////////////////
    
    videoLoop               rdlong  buffer,         displayCounter             ' Download new pixels.
                            add     displayCounter, #4                         '
    
                            or      buffer,         HVSyncColors               ' Update display scanline.
                            waitvid buffer,         #%%3210                    '
    
                            djnz    counter,        #videoLoop                 ' Repeat.
    
    ' //////////////////////Invisible Video////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     vscl,           invisibleScale             ' Set/Reset the video scale.
    
                            waitvid HSyncColors,    syncPixels                 ' Horizontal Sync.
    
    ' //////////////////////Repeat/////////////////////////////////////////////////////////////////////////////////////////////////
    
                            sub     displayCounter, #160                       ' Repeat.
                            djnz    tileCounter,    #tileDisplay               '
    
                            add     displayCounter, #160                       ' Repeat.
                            djnz    tilesCounter,   #tilesDisplay              '
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Inactive Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            add     refreshCounter, #1                         ' Update sync indicator.
                            wrbyte  refreshCounter, syncIndicatorAddress       '
    
    ' //////////////////////Front Porch////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #11                        ' Set loop counter.
    
    frontPorch              mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid HSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Horizontal Sync.
                            waitvid HSyncColors,    syncPixels                 '
    
                            djnz    counter,        #frontPorch                ' Repeat # times.
    
    ' //////////////////////Vertical Sync//////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #(2 + 2)                   ' Set loop counter.
    
    verticalSync            mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid VSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Vertical Sync.
                            waitvid VSyncColors,    syncPixels                 '
    
                            djnz    counter,        #verticalSync              ' Repeat # times.
    
    ' //////////////////////Back Porch/////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,        #31                        ' Set loop counter.
    
    backPorch               mov     vscl,           blankPixels                ' Invisible lines.
                            waitvid HSyncColors,    #0                         '
    
                            mov     vscl,           invisibleScale             ' Horizontal Sync.
                            waitvid HSyncColors,    syncPixels                 '
    
                            djnz    counter,        #backPorch                 ' Repeat # times.
    
    ' //////////////////////Update Display Settings////////////////////////////////////////////////////////////////////////////////
    
                            rdbyte  buffer,         displayIndicatorAddress wz ' Update display settings.
                            muxnz   dira,           directionState             '
    
    ' //////////////////////Loop///////////////////////////////////////////////////////////////////////////////////////////////////
    
                            jmp     #loop                                      ' Loop.
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Data
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    invisibleScale          long    (16 << 12) + 160                           ' Scaling for inactive video.
    visibleScale            long    (4 << 12) + 16                             ' Scaling for active video.
    blankPixels             long    640                                        ' Blank scanline pixel length.
    syncPixels              long    $00_00_3F_FC                               ' F-porch, h-sync, and b-porch.
    HSyncColors             long    $01_03_01_03                               ' Horizontal sync color mask.
    VSyncColors             long    $00_02_00_02                               ' Vertical sync color mask.
    HVSyncColors            long    $03_03_03_03                               ' Horizontal and vertical sync colors.
    
    
    ' //////////////////////Configuration Settings//////////////////////////////////////////
    
    directionState          long    directionstate_const
    videoState              long    videostate_const
    frequencyState          long    frequencystate_const
    
    ' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
    
    displayIndicatorAddress long    displayindicator_const                                
    syncIndicatorAddress    long    syncindicator_const    ' global constant                            
    
    ' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
    
    counter                 res     1
    buffer                  res     1
    
    tileCounter             res     1
    tilesCounter            res     1
    
    refreshCounter          res     1
    displayCounter          res     1
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            fit     496
    '///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '//                                                  TERMS OF USE: MIT License
    '///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    '// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    '// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    '// Software is furnished to do so, subject to the following conditions:
    '//
    '// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    '// Software.
    '//
    '// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    '// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    '// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    '// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    '///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    PASM End
    */
    
    void vga160(char cognumber)                              // function name copied from .spin name above CON section
    {
           /** 
            * @file vga160_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2011, John Doe
            */
           unsigned long vga160_array[] =
           {
               0xa0bffc33, 0xa0bff434, 0x58fff00d, 0xa0fc6a01, 
               0xa0fc7864, 0xa0fc7478, 0xa0fc7204, 0xa0bffe2c, 
               0xa0fc6e28, 0x08bc703c, 0x80fc7804, 0x68bc7031, 
               0xfc7c70e4, 0xe4fc6e09, 0xa0bffe2b, 0xfc3c5e2e, 
               0x84fc78a0, 0xe4fc7207, 0x80fc78a0, 0xe4fc7406, 
               0x80fc7601, 0x003c7636, 0xa0fc6e0b, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e17, 
               0xa0fc6e04, 0xa0bffe2d, 0xfc7c6000, 0xa0bffe2b, 
               0xfc3c602e, 0xe4fc6e1d, 0xa0fc6e1f, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e23, 
               0x02bc7035, 0x7cbfec32, 0x5c7c0004, 0x000100a0, 
               0x00004010, 0x00000280, 0x00003ffc, 0x01030103, 
               0x00020002, 0x03030303, 0x00ff0000, 0x300004ff, 
               0x14242aee, 0x00004e1e, 0x00004e1f
           };
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++)
           {
                  hub_array[i] = vga160_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, cognumber);  // load into cog
    }
    
    void pset(int x, int y, char pixelcolor)                        	//  set pixel at x,y to color %RRGGBBxx x=0 to 159, y=0 to 119
    {
    	int address = graphicstart + x + (y * 160);			// calculate the address - no boundary checks as slows down code
    	*((char *)address) = pixelcolor;					// poke to this location in hub memory 
    }
    
    char rgb(char red, char green, char blue)  // pass red etc 0-255, reduces to 0-3, combines to pixelcolor
    {
    	char pixelcolor;
    	red = red >> 6;                                              // divide by 64 
    	green = green >> 6;
    	blue = blue >> 6;
    	pixelcolor = (red << 6) | (green << 4) | (blue << 2);        // combine together using shifts then or bits
    	return pixelcolor;
    }
    
    void plotbox(int x1, int y1, int x2, int y2, char pixelcolor)		// plot a box, or a line eg horizontal line y1=y2
    {
    	int x;
    	int y;
    	for (x=x1; x<=x2 ;x++)
    		{
    			pset(x,y1,pixelcolor);			      // horizontal lines
    			pset(x,y2,pixelcolor);
    		}
    	for (y=y1+1; y < y2; y++)
    		{
    			pset(x1,y,pixelcolor);				// vertical lines
    			pset(x2,y,pixelcolor);
    		}
    }
    
    void displayclear()	 							// clears to black
    {
    	int address;
    	char pixelcolor = 0;							// black
    	for (address=graphicstart; address < graphicstart+19200; address++)			
    		{
    			*((char *)address) = pixelcolor;			// set to pixelcolor
    		}
    			
    }
    
    // ---------------------------- end vga 160x120 driver methods ------------------------------------------------
    
    // ---------------------------- begin 1280 vga driver ---------------------------------------------------------
    /* PASM Code for compilation using SpinC and inclusion as a data file
    '
    ' VGA 1280x1024 Tile Driver v0.9          by Chip Gracey  Copyright (c) 2006 Parallax, Inc.  22 November 2006
    '
    '                                                                                                                
    ' This object generates a 1280x1024 VGA display from a 80x64 array of 16x16-pixel 4-color tiles.  It requires    
    ' three cogs (or four with optional cursor enabled) and at least 80 MHz.                                         
    
    
    PASM Start vga1280.spin
    CON
      hp = 1280                     'horizontal pixels 1280 x1024
      vp = 1024                     'vertical pixels
      hf = 48                       'horizontal front porch pixels
      hs = 112                      'horizontal sync pixels
      hb = 248                      'horizontal back porch pixels
      vf = 1                        'vertical front porch lines
      vs = 3                        'vertical sync lines
      vb = 38                       'vertical back porch lines
      pr = 100                      'pixel rate in MHz at 80MHz system clock (5MHz granularity)
      ht = hp + hf + hs + hb        'total scan line pixels
      xtiles = hp / 16              ' Tile array
      ytiles = vp / 16
      _clkfreq = 80_000_000                                              ' 5Mhz Crystal
      _clkmode = xtal1 + pll16x                                          ' x 16
                                                                         ' Start of C hub constants
      graphicstart  = 100
      displayindicator_const = 19998
      syncindicator_const = 19999
                                                                         ' End of C constants
    
    PUB Main
        coginit(1,@entry,0)                                           ' cog 1, cogstart, dummy value
    
    DAT
    
    ' ???????????????????????????????
    ' ?  Initialization - all cogs  ?
    ' ???????????????????????????????
    
                            org
    
    ' Move field loop into position
    
    entry                   mov     $1EF,$1EF - field + field_begin                                    
                            sub     entry,d0s0_             '(reverse move to avoid overwrite)             
                            djnz    regs,#entry
    
    ' Build line display code
    
                            mov     par,#xtiles
    :wv                     mov     linecode+0,linecode_wv
                            add     :wv,d1
                            add     linecode_wv,#1
                            cmp     par,#1          wz
    :sc     if_nz           mov     linecode+1,linecode_sc
            if_nz           add     :sc,d1
            if_nz           add     linecode_sc,d1
                            djnz    par,#:wv
    
    ' Acquire settings
                                                            'dira_        ?»  dira
                            mov     regs,par                'dirb_        ?»  dirb
    :next                   movd    :read,sprs              'vcfg_        ?»  vcfg
                            or      :read,d8_d4             'cnt_         ?»  cnt
                            shr     sprs,#4                 'array_ptr_   ?»  ctrb
    :read                   rdlong  dira,regs               'color_ptr_   ?»  frqb
                            add     regs,#4                 'cursor_ptr_  ?»  vscl
                            tjnz    sprs,#:next             'sync_ptr_    ?»  phsb
                            rdlong  regs,regs               'mode_        ?»  regs
    
                            test    regs,#%100      wc      'if mode 1, set tile size to 16 x 32 pixels
            if_c            movs    tile_bytes,#32 * 4
            if_c            shr     array_bytes,#1
                                                            'adjust      cog index
                            test    regs,#%10       wc      'settings    0   1   2
                            test    regs,#%01       wz      '---------------------
            if_nc           add     build,#1                'build      +1  +1  +0                    
            if_nc_and_z     add     vf_lines,#2                                                           
            if_c_and_z      add     vf_lines,#4             'vf_lines   +2  +0  +4                                                    
            if_nc_and_z     sub     vb_lines,#4                                                                                          
            if_nc_and_nz    sub     vb_lines,#2             'vb_lines   -4  -2  -0                                                    
            if_nc_and_nz    movs    start_line,#2 * 4                                        
            if_c_and_z      movs    start_line,#4 * 4       'start_line +0  +2  +4
            
            if_c_or_z       mov     snop,#0                 'sync        N   Y   N                   
    
                            mov     regs,vscl               'save cursor pointer
                                                                                    
    ' Synchronize all cogs' video circuits so that waitvid's will be pixel-locked
                                                                                                  
                            movi    frqa,#(pr / 5) << 1     'set pixel rate (VCO runs at 1x)                     
                            mov     vscl,#1                 'set video shifter to reload on every pixel
                            waitcnt cnt,d8_d4               'wait for sync count, add ~3ms - cogs locked!
                            movi    ctra,#%00001_111        'enable PLLs now - NCOs locked!
                            waitcnt cnt,#0                  'wait ~3ms for PLLs to stabilize - PLLs locked!
                            mov     vscl,#100               'subsequent WAITVIDs will now be pixel-locked!
    
    ' Determine if this cog is to perform one of two field functions or the cursor function
    
            if_nc_or_z      jmp     #vsync                  'if cog index 0..2, jump to field function
                                                            'else, cursor function follows
    
    ' ???????????????????????????
    ' ?  Cursor Loop - one cog  ?
    ' ???????????????????????????
    
    ' Do vertical sync lines minus two
    
    cursor                  mov     par,#vf + vs + vb - 5
    
    :loop                   mov     vscl,vscl_line
    :vsync                  waitvid ccolor,#0
                            djnz    par,#:vsync
    
    ' Do two lines minus horizontal back porch pixels to buy a big block of time
    
                            mov     vscl,vscl_two_lines_mhb
                            waitvid ccolor,#0   
    
    ' Get cursor data
    
                            rdlong  cx,regs                 'get cursor x
                            add     regs,#4
                            rdlong  cy,regs                 'get cursor y
                            add     regs,#4
                            rdlong  ccolor,regs             'get cursor color
                            add     regs,#4
                            rdlong  cshape,regs             'get cursor shape
                            sub     regs,#3 * 4
    
                            and     ccolor,#$FC             'trim and justify cursor color
                            shl     ccolor,#8
    
    ' Build cursor pixels
    
                            mov     par,#32                 'ready for 32 cursor segments
                            movd    :pix,#cpix
                            mov     cnt,cshape
                            
    :pixloop                cmp     cnt,#1          wc, wz  'arrow, crosshair, or custom cursor?
            if_a            jmp     #:custom
            if_e            jmp     #:crosshair
            
                            cmp     par,#32         wz      'arrow
                            cmp     par,#32-21      wc      
            if_z            mov     cseg,h80000000
            if_nz_and_nc    sar     cseg,#1
            if_nz_and_c     shl     cseg,#2
                            mov     coff,#0
                            jmp     #:pix
                            
    :crosshair              cmp     par,#32-15      wz      'crosshair
            if_ne           mov     cseg,h00010000
            if_e            neg     cseg,#2
                            cmp     par,#1          wz
            if_e            mov     cseg,#0
                            mov     coff,h00000F0F
                            jmp     #:pix
                            
    :custom                 rdlong  cseg,cshape             'custom
                            add     cshape,#4
                            rdlong  coff,cshape
                            
    :pix                    mov     cpix,cseg               'save segment into pixels
                            add     :pix,d0
                            
                            djnz    par,#:pixloop           'another segment?
    
    ' Compute cursor position
    
                            mov     cseg,coff               'apply cursor center-pixel offsets
                            and     cseg,#$FF
                            sub     cx,cseg
                            shr     coff,#8
                            and     coff,#$FF
                            add     cy,coff
    
                            cmps    cx,neg31        wc      'if x out of range, hide cursor via y
            if_nc           cmps    pixels_m1,cx    wc
            if_c            neg     cy,#1
    
                            mov     cshr,#0                 'adjust for left-edge clipping               
                            cmps    cx,#0           wc
            if_c            neg     cshr,cx
            if_c            mov     cx,#0
            
                            mov     cshl,#0                 'adjust for right-edge clipping
                            cmpsub  cx,pixels_m32   wc
            if_c            mov     cshl,cx
            if_c            mov     cx,pixels_m32
    
                            add     cx,#hb                  'bias x and y for display
                            sub     cy,lines_m1
    
    ' Do visible lines with cursor
    
                            mov     par,lines               'ready for visible scan lines
    
    :line                   andn    cy,#$1F         wz, nr  'check if scan line in cursor range
    
            if_z            movs    :seg,cy                 'if in range, get cursor pixels
            if_z            add     :seg,#cpix
            if_nz           mov     cseg,#0                 'if out of range, use blank pixels
    :seg    if_z            mov     cseg,cpix
            if_z            rev     cseg,#0                 'reverse pixels so they map sensibly
            if_z            shr     cseg,cshr               'perform any edge clipping on pixels
            if_z            shl     cseg,cshl
    
                            mov     vscl,cx                 'do left blank pixels (hb+cx)
                            waitvid ccolor,#0
                            
                            mov     vscl,vscl_cursor        'do cursor pixels (32)
                            waitvid ccolor,cseg
                            
                            mov     vscl,vscl_line_m32      'do right blank pixels (hp+hf+hs-32-cx)
                            sub     vscl,cx
                            waitvid ccolor,#0
    
                            add     cy,#1                   'another scan line?
                            djnz    par,#:line
    
    ' Do horizontal back porch pixels and loop
    
                            mov     vscl,#hb
                            waitvid ccolor,#0
    
                            mov     par,#vf + vs + vb - 2   'ready to do vertical sync lines
                            jmp     #:loop
    
    ' Cursor data
    
    vscl_line               long    ht                      'total pixels per scan line
    vscl_two_lines_mhb      long    ht * 2 - hb             'total pixels per two scan lines minus hb
    vscl_line_m32           long    ht - 32                 'total pixels per scan line minus 32
    vscl_cursor             long    1 << 12 + 32            '32 pixels per cursor with 1 clock per pixel
    lines                   long    vp                      'visible scan lines
    lines_m1                long    vp - 1                  'visible scan lines minus 1
    pixels_m1               long    hp - 1                  'visible pixels minus 1
    pixels_m32              long    hp - 32                 'visible pixels minus 32
    neg31                   long    -31
                        
    h80000000               long    $80000000               'arrow/crosshair cursor data
    h00010000               long    $00010000
    h00000F0F               long    $00000F0F
    
    ' Initialization data
    
    d0s0_                   long    1 << 9 + 1              'd and s field increments
    regs                    long    $1F0 - field            'number of registers in field loop space
    sprs                    long    $DFB91E76               'phsb/vscl/frqb/ctrb/cnt/vcfg/dirb/dira nibbles
    bit15                   long    $8000                   'bit15 mask used to differentiate cogs in par
    d8_d4                   long    $0003E000               'bit8..bit4 mask for d field
    
    field_begin                                             'field code begins at this offset
    
    ' Undefined cursor data
    
    cx                      res     1
    cy                      res     1
    ccolor                  res     1
    cshape                  res     1
    coff                    res     1
    cseg                    res     1
    cshr                    res     1
    cshl                    res     1
    cpix                    res     32
    
    
    ' ?????????????????????????????
    ' ?  Field Loop - three cogs  ?
    ' ?????????????????????????????
    
                            org
    
    ' Allocate buffers
    
    palettes                res     64                      'palettes of colors
    
    pixels0                 res     xtiles                  'pixels for tile row line +0
    pixels1                 res     xtiles                  'pixels for tile row line +1
    
    linecode                res     xtiles * 2 - 1          'line display code
    field                   mov     vscl,#hf
                            waitvid hv_sync,#0
    linecode_sc             sumc    linecode,#xtiles        '(winds up as 'sumc field-1,#xtiles')
                            mov     ina,#1
                            jmp     #hsync
    
    linecode_wv             waitvid palettes,pixels0
    
    ' Each cog alternately builds and displays two scan lines
                              
    build                   mov     cnt,#vp / 6             'ready number of two-scan-line builds/displays
    start_line              mov     tile_line,#0            'ready starting tile line (adjusted)
                            
    ' Build two scan lines during four scan lines
    
    build_2y                movd    col,#linecode           'reset pointers for scan line buffers 
                            movd    pix0,#pixels0          
                            movd    pix1,#pixels1          
    
                            mov     ina,#2                  'two scan lines require two waitvid's
    
    build_40x               mov     vscl,vscl_two_lines     'output lows for two scan lines so other cog
    :zero                   waitvid :zero,#0                '..can display while this cog builds (twice)
    
                            mov     inb,#xtiles / 2         'build four scan lines for half a row
    
    build_1x                rdword  vscl,ctrb               'get word from the tile array
                            add     ctrb,#2                  
                            ror     vscl,#10                'get color bits
    col                     movd    linecode,vscl
                            add     col,d1
                            shr     vscl,#16                'get tile line address
                            add     vscl,tile_line                                   
    pix0                    rdlong  pixels0,vscl            'get line +0 tile pixels
                            add     pix0,d0                                  
                            add     vscl,#4                                  
    pix1                    rdlong  pixels1,vscl            'get line +1 tile pixels                 
                            add     pix1,d0                                  
                            djnz    inb,#build_1x           'loop for next tile (16 inst/loop)
    
                            djnz    ina,#build_40x          'if first half done, loop for 2nd waitvid
                            
                            sub     ctrb,#xtiles * 2        'back up to start of same row
    
    ' Display two scan lines
    
                            mov     inb,#2                  'ready for two scan lines
                            movs    hsync_ret,#linecode_ret
    
    display                 test    inb,#1          wc
                            mov     vscl,vscl_tile          'set pixel rate for tiles
                            jmp     #linecode
    linecode_ret            djnz    inb,#display            'another scan line?
    
    ' Another two scan lines?
                                 
                            add     tile_line,#6 * 4        'advance six scan lines within tile row
    tile_bytes              cmpsub  tile_line,#16 * 4 wc    'tile row done? (# doubled for mode 1)
            if_c            add     ctrb,#xtiles * 2        'if done, advance array pointer to next row
    
                            djnz    cnt,#build_2y           'another two scan lines?
    
                            sub     ctrb,array_bytes        'display done, reset array pointer to top row                  
    
    ' Visible section done, handle sync indicator
    
                            cmp     cnt,phsb        wz      'sync enabled? (cnt=0)
    snop    if_nz           wrlong  neg1,phsb               'if so, write -1 to sync indicator (change to nop unless #3)
    
    ' Do vertical sync lines and loop
                            
    vf_lines                mov     ina,#vf                 'do vertical front porch lines (adjusted +4|+2|+0)
                            call    #blank
    
    vsync                   mov     ina,#vs                 'do vertical sync lines
                            call    #blank_vsync
    
    vb_lines                mov     ina,#vb                 'do vertical back porch lines (adjusted -4|-2|-0)
                            movs    blank_vsync_ret,#build  '(loop to build, blank_vsync follows)
    
    ' Subroutine - do blank lines
    
    blank_vsync             xor     hv_sync,#$0101          'flip vertical sync bits
    
    blank                   mov     vscl,vscl_blank         'do horizontal blank pixels
                            waitvid hv_sync,#0
    
                            mov     vscl,#hf                'do horizontal front porch pixels
                            waitvid hv_sync,#0
    
    hsync                   mov     vscl,#hs                'do horizontal sync pixels
                            waitvid hv_sync,#1
    
                            rdlong  vscl,frqb               'update another palette
                            and     vscl,color_mask
    :palette                mov     palettes,vscl
                            add     :palette,d0
                            add     frqb,#4
                            add     par,count_64    wc      
            if_c            movd    :palette,#palettes
            if_c            sub     frqb,#64 * 4
    
                            mov     vscl,#hb                'do horizontal back porch pixels
                            waitvid hv_sync,#0
                            
                            djnz    ina,#blank              'another blank line?
    hsync_ret           
    blank_ret
    blank_vsync_ret         ret
    
    ' Field data
    
    d0s0                    long    1 << 9 + 1              'd and s field increments
    d0                      long    1 << 9                  'd field increment
    d1                      long    1 << 10                 'd field double increment
    
    array_bytes             long    xtiles * ytiles * 2     'number of bytes in tile array
    
    vscl_two_lines          long    ht * 2                  'total pixels per two scan lines
    vscl_tile               long    1 << 12 + 16            '16 pixels per tile with 1 clock per pixel
    vscl_blank              long    hp                      'visible pixels per scan line
    
    hv_sync                 long    $0200                   '+/-H,-V states
    count_64                long    $04000000               'addend that sets carry every 64th addition
    color_mask              long    $FCFCFCFC               'mask to isolate R,G,B bits from H,V
    neg1                    long    $FFFFFFFF               'negative 1 to be written to sync indicator
    
    ' Undefined field data
    
    tile_line               res     1
                      	   fit     496
    
    '///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '//                                                  TERMS OF USE: MIT License
    '///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    '// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    '// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    '// Software is furnished to do so, subject to the following conditions:
    '//
    '// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    '// Software.
    '//
    '// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    '// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    '// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    '// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    '///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    PASM End
    */
    
    void vga1280(char cognumber)                              // function name copied from .spin name above CON section
    {
           /** 
            * @file vga1280_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2011, John Doe
            */
           unsigned long vga1280_array[] =
           {
               0xa0bfdefd, 0x84bc0088, 0xe4fd1200, 0xa0ffe050, 
               0xa0bdc184, 0x80bc09c5, 0x80ff0801, 0x867fe001, 
               0xa095c381, 0x809411c5, 0x809703c5, 0xe4ffe004, 
               0xa0bd13f0, 0x54bc208a, 0x68bc208c, 0x28fd1404, 
               0x08bfec89, 0x80fd1204, 0xe87d140d, 0x08bd1289, 
               0x617d1204, 0x50f34880, 0x28f38c01, 0x617d1202, 
               0x627d1201, 0x80cf0a01, 0x80cb5402, 0x80e35404, 
               0x84cb5c04, 0x84c75c02, 0x50c70c08, 0x50e30c10, 
               0xa0fb5200, 0xa0bd13ff, 0x58fff428, 0xa0fffe01, 
               0xf8bfe28c, 0x58fff00f, 0xf8ffe200, 0xa0fffe64, 
               0x5c6c01ac, 0xa0ffe025, 0xa0bffe7c, 0xfc7d1e00, 
               0xe4ffe02b, 0xa0bffe7d, 0xfc7d1e00, 0x08bd1a89, 
               0x80fd1204, 0x08bd1c89, 0x80fd1204, 0x08bd1e89, 
               0x80fd1204, 0x08bd2089, 0x84fd120c, 0x60fd1efc, 
               0x2cfd1e08, 0xa0ffe020, 0x54fca095, 0xa0bfe290, 
               0x877fe201, 0x5c44004d, 0x5c680046, 0x867fe020, 
               0x857fe00b, 0xa0a92485, 0x38c52401, 0x2cd12402, 
               0xa0fd2200, 0x5c7c0050, 0x867fe011, 0xa0952486, 
               0xa4e92402, 0x867fe001, 0xa0e92400, 0xa0bd2287, 
               0x5c7c0050, 0x08bd2490, 0x80fd2004, 0x08bd2290, 
               0xa0bd2a92, 0x80bca1c4, 0xe4ffe03c, 0xa0bd2491, 
               0x60fd24ff, 0x84bd1a92, 0x28fd2208, 0x60fd22ff, 
               0x80bd1c91, 0xc13d1a84, 0xc10d048d, 0xa4f11c01, 
               0xa0fd2600, 0xc17d1a00, 0xa4b1268d, 0xa0f11a00, 
               0xa0fd2800, 0xe1bd1a83, 0xa0b1288d, 0xa0b11a83, 
               0x80fd1af8, 0x84bd1c81, 0xa0bfe080, 0x667d1c1f, 
               0x50a8d68e, 0x80e8d695, 0xa0d52400, 0xa0a92495, 
               0x3ce92400, 0x28a92493, 0x2ca92494, 0xa0bffe8d, 
               0xfc7d1e00, 0xa0bffe7f, 0xfc3d1e92, 0xa0bffe7e, 
               0x84bffe8d, 0xfc7d1e00, 0x80fd1c01, 0xe4ffe067, 
               0xa0fffef8, 0xfc7d1e00, 0xa0ffe028, 0x5c7c002a, 
               0x00000698, 0x00000c38, 0x00000678, 0x00001020, 
               0x00000400, 0x000003ff, 0x000004ff, 0x000004e0, 
               0xffffffe1, 0x80000000, 0x00010000, 0x00000f0f, 
               0x00000201, 0x00000071, 0xdfb91e76, 0x00008000, 
               0x0003e000, 0xa0fffe30, 0xfc7f9400, 0x90fdc050, 
               0xa0ffe401, 0x5c7c01b5, 0xfc3c0040, 0xa0ffe2aa, 
               0xa0ff9c00, 0x54ff22e0, 0x54ff2a40, 0x54ff3090, 
               0xa0ffe402, 0xa0bfffc7, 0xfc7f1800, 0xa0ffe628, 
               0x04bffff9, 0x80fff202, 0x20fffe0a, 0x54bdc1ff, 
               0x80bf23c5, 0x28fffe10, 0x80bfffce, 0x08bc81ff, 
               0x80bf2bc4, 0x80fffe04, 0x08bd21ff, 0x80bf31c4, 
               0xe4ffe78e, 0xe4ffe58b, 0x84fff2a0, 0xa0ffe602, 
               0x50ff85a2, 0x617fe601, 0xa0bfffc8, 0x5c7c00e0, 
               0xe4ffe79f, 0x80ff9c18, 0xe1ff9c40, 0x80f3f2a0, 
               0xe4ffe387, 0x84bff3c6, 0x863fe3fd, 0x08179bfd, 
               0xa0ffe401, 0x5cff85b1, 0xa0ffe403, 0x5cff85b0, 
               0xa0ffe426, 0x50ff8585, 0x6cff9501, 0xa0bfffc9, 
               0xfc7f9400, 0xa0fffe30, 0xfc7f9400, 0xa0fffe70, 
               0xfc7f9401, 0x08bffffb, 0x60bfffcc, 0xa0bc01ff, 
               0x80bf73c4, 0x80fff604, 0x81bfe1cb, 0x54f37200, 
               0x84f3f700, 0xa0fffef8, 0xfc7f9400, 0xe4ffe5b1, 
               0x5c7c0000, 0x00000201, 0x00000200, 0x00000400, 
               0x00002800, 0x00000d30, 0x00001010, 0x00000500, 
               0x00000200, 0x04000000, 0xfcfcfcfc, 0xffffffff
           };
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++)
           {
                  hub_array[i] = vga1280_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, cognumber);  // load into cog
    }
    
    // ---------------------------- end 1280 vga driver ---------------------------------------------------------
    
    void displayicon(int x,int y)					// 32x32 bit icon created from the Visual IDE tab and copied here. Display at x,y
    {
    	int r;
    	int c;
    	int i;
    										// File c:\program files\catalina\demos\tweety32.h
         char tweety[] =
           {
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xac, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xa0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe4, 0xa8, 0xa4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xa8, 0xfc, 0xb8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0x68, 0xac, 0xb8, 0xf0, 0xf0, 0xf0, 0xa4, 0xa4, 0xa4, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0x18, 0x68, 0xa8, 0xf0, 0xf0, 0xa8, 0xfc, 0xa8, 0xe0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf4, 0xf0, 0xf0, 0xf0, 0x18, 0x68, 0xf4, 0xf0, 0xa4, 0x6c, 0xbc, 0xe4, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xa4, 0xa8, 0xf0, 0xf0, 0x14, 0x68, 0xe4, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0x58, 0xe4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xf0, 0xe0, 0xe4, 0xe0, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf4, 0xf8, 0xf8, 0xf8, 0xf4, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf0, 0xf0, 0xfc, 0xfc, 0xf4, 0xf0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe4, 0xf0, 0xf0, 0xf4, 0xfc, 0xf4, 0xf0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xe0, 0xa0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf4, 0xf0, 0xf8, 0xf0, 0xf0, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe4, 0xe4, 0xf0, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xe4, 0xe4, 0xe4, 0xf8, 0xfc, 0xfc, 0xfc, 0xe4, 0xe8, 0xe4, 0xfc, 0xfc, 0xf8, 0xe8, 0xe4, 0xe4, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe8, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xfc, 0xe8, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
              0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe8, 0xe4, 0xe4, 0xe4, 0xe8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xe8, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
           };
    	i=0;									// counter
           for(r=0; r<32; r++)							// count rows
    	{
    		for(c=0; c<32; c++)						// column counter
    		{
    			pset(x+c,r+y,tweety[i]);
    			i++;							// increment counter
    		}
    	}
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                   t_setpos(0,0,i);                                      // move cursor to next line
                   t_color(0,0x08FC);                                    // RRGGBBxx eg dark blue background 00001000 white text 11111100
           }
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    void stopallcogs()								// stop all cogs except the one running C
    {
    	int i;
    	int c;								       // cog running C
    	c=_cogid();
    	for(i=0;i<8;i++)
    	{
    		if(i != c)
    		{
    			_cogstop(i);						// stop this cog if not the one running C
    		}
    	}
    }
    
    void main ()
    {
    	int i;
    	clearscreen();
           printf("Clock speed %u \n",_clockfreq());                     // see page 28 of the propeller manual for other useful commands
           printf("Catalina running in cog number %i \n",_cogid());      // integer
    	sleep(4000); 								// for CRT display to warm up
    	stopallcogs(); 							// stop all cogs except C one
           vga160(7);                                                    // start 160x120 graphic driver in cog 7
    	displayclear();							// clear the display
    	plotbox(0,0,159,119,rgb(255,0,0));					// draw a box in red round the edge of the screen
    //	pset(0,0,0xff);  							// top left corner to white
    //	pset(0,119,rgb(0,255,0));   					// set pixel to red green blue value bottom left corner
    //	pset(159,0,rgb(0,0,255)); 						// top right corner
    //	pset(159,119,rgb(255,255,0)); 					// bottom right corner
    	displayicon(50,50);							// display 32x32 picture
    	plotbox(49,49,82,82,rgb(0,255,0));				// draw a box around the picture
           while (1);                                                    // Prop reboots on exit from main()
    }
    

    This is the working Kye driver and the beginnings of the 1280 vga text driver. I have been rereading post #493 about where things get stored, and in general I want to keep as much as possible in XMM.

    So regarding this code:

    1) Near the bottom is a large array called "tweety" which prints tweety bird on the screen. I have a feeling this is being stored in hub on the stack. If this is correct, what do you think is better - define this as a global array so it ends up in XMM, or define it locally with the malloc example?

    2) I am confused about where the program data is being stored
    void vga160(char cognumber)                              // function name copied from .spin name above CON section
    {
           /** 
            * @file vga160_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2011, John Doe
            */
           unsigned long vga160_array[] =
           {
               0xa0bffc33, 0xa0bff434, 0x58fff00d, 0xa0fc6a01, 
               0xa0fc7864, 0xa0fc7478, 0xa0fc7204, 0xa0bffe2c, 
               0xa0fc6e28, 0x08bc703c, 0x80fc7804, 0x68bc7031, 
               0xfc7c70e4, 0xe4fc6e09, 0xa0bffe2b, 0xfc3c5e2e, 
               0x84fc78a0, 0xe4fc7207, 0x80fc78a0, 0xe4fc7406, 
               0x80fc7601, 0x003c7636, 0xa0fc6e0b, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e17, 
               0xa0fc6e04, 0xa0bffe2d, 0xfc7c6000, 0xa0bffe2b, 
               0xfc3c602e, 0xe4fc6e1d, 0xa0fc6e1f, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e23, 
               0x02bc7035, 0x7cbfec32, 0x5c7c0004, 0x000100a0, 
               0x00004010, 0x00000280, 0x00003ffc, 0x01030103, 
               0x00020002, 0x03030303, 0x00ff0000, 0x300004ff, 
               0x14242aee, 0x00004e1e, 0x00004e1f
           };
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++)
           {
                  hub_array[i] = vga160_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, cognumber);  // load into cog
    }
    

    I think the point of moving it from the locally defined array to the hubarray was to move it from xmm to hub. But on reading that previous post, I am wondering if both are in hub? Do I again need to use malloc, or put the array outside a function?

    3) I'd like to pass some parameters to the cog.
    unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
    

    passes some fixed values. In keeping with the C concept of keeping everything modular, would a better way be to create an array in XMM with some variable data that we might calculate (copied from spin), then pass a pointer to this loading function, which then copies the array to a hub array, and then pass the start of that location to _coginit.

    There are a number of Spin objects where one creates a contiguous list of longs, puts variables in that list (I've been using constants but sooner or later I have to move to variables), then pass a pointer to the start of that list via 'par'.

    Your advice would be most appreciated.

    Addit: I went out and mowed the lawns and had a bit more of a think. What I think happens in XMM is you have a declaration of an array with some code. The data for that resides in XMM. The program gets to the function and finds there is an array and there is some data for that array. So it declares the array and moves the data onto the stack. It is now in hub ram but in the stack part of hub ram. Then I think the data gets moved to another array in hub ram - I'll have to think about that a little more...

    Addit Addit:

    Thinking through the above further, I replaced this code:
    void vga160()                                                     // unique name for each loader
    {
           /** 
            * @file vga160_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2010, John Doe
            */
           unsigned long vga160_array[] =
           {
               0xa0bffc33, 0xa0bff434, 0x58fff00d, 0xa0fc6a01, 
               0xa0fc7800, 0xa0fc7478, 0xa0fc7204, 0xa0bffe2c, 
               0xa0fc6e28, 0x08bc703c, 0x80fc7804, 0x68bc7031, 
               0xfc7c70e4, 0xe4fc6e09, 0xa0bffe2b, 0xfc3c5e2e, 
               0x84fc78a0, 0xe4fc7207, 0x80fc78a0, 0xe4fc7406, 
               0x80fc7601, 0x003c7636, 0xa0fc6e0b, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e17, 
               0xa0fc6e04, 0xa0bffe2d, 0xfc7c6000, 0xa0bffe2b, 
               0xfc3c602e, 0xe4fc6e1d, 0xa0fc6e1f, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e23, 
               0x02bc7035, 0x7cbfec32, 0x5c7c0004, 0x000100a0, 
               0x00004010, 0x00000280, 0x00003ffc, 0x01030103, 
               0x00020002, 0x03030303, 0x00ff0000, 0x300004ff, 
               0x14242aee, 0x00004b00, 0x00004b01
           };
           unsigned long hub_array[512];
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           int i;
           for (i = 0; i < 512; i++)
           {
                  hub_array[i] = vga160_array[i];
           }
           _coginit((int)par_cogject>>2, (int)hub_array>>2, 7);          // load into cog 7
    }
    

    with this code
    void vga160(char cognumber)                              // function name copied from .spin name above CON section
    {
           /** 
            * @file vga160_array.h
            * Created with spin.binary PASM to C Array Converter.
            * Copyright (c) 2011, John Doe
            */
           unsigned long vga160_array[] =
           {
               0xa0bffc33, 0xa0bff434, 0x58fff00d, 0xa0fc6a01, 
               0xa0fc7864, 0xa0fc7478, 0xa0fc7204, 0xa0bffe2c, 
               0xa0fc6e28, 0x08bc703c, 0x80fc7804, 0x68bc7031, 
               0xfc7c70e4, 0xe4fc6e09, 0xa0bffe2b, 0xfc3c5e2e, 
               0x84fc78a0, 0xe4fc7207, 0x80fc78a0, 0xe4fc7406, 
               0x80fc7601, 0x003c7636, 0xa0fc6e0b, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e17, 
               0xa0fc6e04, 0xa0bffe2d, 0xfc7c6000, 0xa0bffe2b, 
               0xfc3c602e, 0xe4fc6e1d, 0xa0fc6e1f, 0xa0bffe2d, 
               0xfc7c5e00, 0xa0bffe2b, 0xfc3c5e2e, 0xe4fc6e23, 
               0x02bc7035, 0x7cbfec32, 0x5c7c0004, 0x000100a0, 
               0x00004010, 0x00000280, 0x00003ffc, 0x01030103, 
               0x00020002, 0x03030303, 0x00ff0000, 0x300004ff, 
               0x14242aee, 0x00004e1e, 0x00004e1f
           };
           unsigned long par_cogject[] = { 1, 2, 3 };                    // data to pass to cog - ignore if not used
           _coginit((int)par_cogject>>2, (int)vga160_array>>2, cognumber);  // load into cog
    }
    

    and it still seems to work. I presume that the act of declaring an array in a local function moves the array from data within XMM to the stack, and if we start _coginit pointing to that array in the stack it will still load?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-08 05:28
    I hope Ross comes back from his break soon!

    Working on translating Obex code into C. I've been building a structure such that the C code ends up similar to the Spin code. That involves passing parameters and having common memory locations. Lots of fun and it is great as more things come together.

    I gather that the propeller stores longs in 'little endian' format. I wrote a 'pokelong' routine to do this one byte at a time. I tried doing this with one line but it didn't work. So this is the warts and all code and it has been tested. Any C experts see a way to simplify the pokelong routine?
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void pokelong(int address, unsigned long value)                      // function poke a long value to hub ram little endian first
    {
           char c;
    	c = value & 0x000000FF; // mask
    	poke(address,c);
    	value = value >> 8; // bit shift
    	c = value & 0x000000FF; // mask
    	poke(address+1,c);
    	value = value >> 8; // bit shift
    	c = value & 0x000000FF; // mask
    	poke(address+2,c);
    	value = value >> 8; // bit shift
    	c = value & 0x000000FF; // mask
    	poke(address+3,c);
    }
    

    Addit:

    This seems to work
    void pokelong(int address, unsigned long value) // poke long to hub ram
    {
           *((unsigned long *)address) = value;
    }
    

    I think this can become the building block for passing parameters.

    Typical Spin code:
    * Define a list of global variables in a Var section
    * Fill them up in a Start routine
    * Start a cog and pass the 'par' as the first variable in that Var section

    This then passes as many variables in that Var list as the cog needs to use.

    Translating this to C:
    * Define a global constant at a known hub location (cogs may want exclusive use of this location)
    * Define a list of unsigned longs in a Start function
    * Poke them individually to the hub ram at the global constant location, as many as required
    * Point variable 'parameters' to the beginning of the list
    * Call the function to load the cog. Pass two variables - cog number and parameter eg void vga1280(char cognumber, unsigned long parameters)
    * cog loader contains compiled pasm code.
    * point 'par_cogject' array to paramters
    * load the cog
           unsigned long par_cogject[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };                    // data to pass to cog - ignore if not used
           _coginit((int)par_cogject>>2, (int)vga1280_array>>2, cognumber);  // load into cog
    

    For cog code that just needs a list of values passed but no reserved hub ram, there are the plugins.

    For situations where the cog also needs fixed hub locations and needs exclusive use of those (eg video drivers needing video buffer space), use the above code.

    One slightly complicated task is working out which of these two is best for a typical piece of obex code. Need to go through all the code looking for other references for passed variables to see if they are exclusively using fixed hub locations.

    I'm working on translating this to C:
    VAR
    
      long cog[4]
      
      long dira_                    '9 contiguous longs
      long dirb_
      long vcfg_
      long cnt_
      long array_ptr_
      long color_ptr_
      long cursor_ptr_
      long sync_ptr_
      long mode_ 
      
    
    PUB start(base_pin, array_ptr, color_ptr, cursor_ptr, sync_ptr, mode) : okay | i, j
    
    '' Start driver - starts two or three cogs
    '' returns false if cogs not available
    '' 
    ''     base_pin = First of eight VGA pins, must be a multiple of eight (0, 8, 16, 24, etc):
    ''                                           
    ''                    240&#937;               240&#937;                 240&#937;                240&#937;                  
    ''                +7 &#61609;&#9472;&#61629;&#61630;&#9472;&#9472;&#9523;&#9472;&#61627; Red   +5 &#61609;&#9472;&#61629;&#61630;&#9472;&#9472;&#9523;&#9472;&#61627; Green   +3 &#61609;&#9472;&#61629;&#61630;&#9472;&#9472;&#9523;&#9472;&#61627; Blue   +1 &#61609;&#9472;&#61629;&#61630;&#9472;&#61627; H        
    ''                    470&#937; &#9474;             470&#937; &#9474;               470&#937; &#9474;              240&#937;                  
    ''                +6 &#61609;&#9472;&#61629;&#61630;&#9472;&#9472;&#9496;         +4 &#61609;&#9472;&#61629;&#61630;&#9472;&#9472;&#9496;           +2 &#61609;&#9472;&#61629;&#61630;&#9472;&#9472;&#9496;          +0 &#61609;&#9472;&#61629;&#61630;&#9472;&#61627; V         
    ''  
    ''    array_ptr = Pointer to 5,120 long-aligned words, organized as 80 across by 64 down,
    ''                which will serve as the tile array. Each word specifies a tile bitmap and
    ''                a color palette for its tile area. The bottom 10 bits of each word hold
    ''                the base address of a 16-long tile bitmap, while the top 6 bits select a
    ''                color palette for the bitmap. For example, $B2E5 would specify the tile
    ''                bitmap spanning $B940..$B97F ($2E5<<6) and color palette $2C ($B2E5>>10).
    ''  
    ''    color_ptr = Pointer to 64 longs which will define the 64 color palettes. The RGB data
    ''                in each long is arranged as %%RGBx_RGBx_RGBx_RGBx with the sub-bytes 3..0
    ''                providing the color data for pixel values %11..%00, respectively:
    ''  
    ''                %%3330_0110_0020_3300: %11=white, %10=dark cyan, %01=blue, %00=gold
    ''  
    ''   cursor_ptr = Pointer to 4 longs which will control the cursor, or 0 to disable the
    ''                cursor. If a pointer is given, an extra cog will be started to generate
    ''                the cursor overlay. Here are the 4 longs that control the cursor:
    '' 
    ''                cursor_x      - X position of cursor: ..0..1279.. (left to right)
    ''                cursor_y      - Y position of cursor: ..0..1023.. (bottom to top)
    ''
    ''                cursor_color  - Cursor color to be OR'd to background color as %%RGBx:
    ''                                %%3330=white, %%2220 or %%1110=translucent, %%0000=off
    ''
    ''                cursor_shape  - 0 for arrow, 1 for crosshair, or pointer to a cursor
    ''                                definition. A cursor definition consists of 32 longs
    ''                                containing a 32x32 pixel cursor image, followed by two
    ''                                bytes which define the X and Y center-pixel offsets
    ''                                within the image.
    ''
    ''     sync_ptr = Pointer to a long which will be set to -1 after each refresh, or 0 to
    ''                disable this function. This is useful in advanced applications where
    ''                awareness of display timing is important.
    ''  
    ''         mode = 0 for normal 16x16 pixel tiles or 1 for taller 16x32 pixel tiles. Mode 1
    ''                is useful for displaying the internal font while requiring half the array
    ''                memory; however, the 3-D bevel characters will not be usable because of
    ''                the larger vertical tile granularity of this mode.
                                                                                                       
      'If driver is already running, stop it
      stop
    
      'Ready i/o settings
      i := $FF << (base_pin & %011000)
      j := base_pin & %100000 == 0
      dira_ := i & j
      dirb_ := i & !j
      vcfg_ := $300000FF + (base_pin & %111000) << 6
    
      'Ready cnt value to sync cogs by
      cnt_ := cnt + $100000
    
      'Ready pointers and mode
      longmove(@array_ptr_, @array_ptr, 5)
    
      'Launch cogs, abort if error
      j := mode_
      repeat i from 0 to 3
        mode_ := j << 2 + i
        if i == 3                   'cursor cog?
          ifnot cursor_ptr          'cursor enabled?
            quit                    'if not, quit loop
          vcfg_ ^= $10000000        'else, set two-color mode
        ifnot cog[i] := cognew(@entry, @dira_) + 1
          stop
          return {false}
        waitcnt($8000 + cnt)        'allow cog to launch before modifying variables
    
      'Successful
      return true
    
  • RossHRossH Posts: 5,580
    edited 2011-01-08 15:59
    Hi Dr_Acula,

    I'm back. I have some work I need to do today, but I'll try and get a chance to answer your questions later today.

    Ross.
  • RossHRossH Posts: 5,580
    edited 2011-01-08 21:42
    Hi Dr_Acula,

    Regarding your questions in post #568: Mostly you have answered them yourself - but just to confirm:

    1. Yes, if your program is compiled in XMM mode, then the array "tweety" is indeed being created on the stack. But this array has an initializer (i.e. the values 0xfc etc) which will be in XMM RAM anyway, and get copied to the array on the stack at run time - so you may as well make the array global (i.e. give it file scope) and put the whole array in XMM RAM - this actually saves both time and space.

    2. No, you don't need to do the copy here - as I mentioned in the answer to 1 (above) - if a local array has an initializer, that initializer will be in XMM RAM, but the compiler will copy it to the stack (i.e. hub RAM) for you at run time.

    3. When calling another language from C, one way to make sure the variables you want to pass are physically located where you want them is to declare a structure in C with the appropriate memory layout, fill in the values at run time, and pass a pointer to the structure. For example:

    // declare a structre to ensure our 3 values are layed out correctly
    typedef struct {
       int val1;
       int val2;
       int val3;
    } val_type;
    
    // this function gets values out of the structure given a pointer to it
    void func (val_type *v) {
       int v1;
       int v2;
       int v3;
    
       v1 = v->val1;
       v2 = v->val2;
       v3 = v->val3;
    }
    
    void main() {
    
       // declare an instance of the structure
       val_type v;
    
       // fill it in
       v.val1 = 1;
       v.val2 = 2;
       v.val3 = 3;
    
       // pass the address to a function (which may be written in another language!)
       func(&v);
    }
    

    Ross.
Sign In or Register to comment.