Shop OBEX P1 Docs P2 Docs Learn Events
Propeller assembly in a cog, interfaced to either Catalina or propeller-gcc. — Parallax Forums

Propeller assembly in a cog, interfaced to either Catalina or propeller-gcc.

FastrobotFastrobot Posts: 51
edited 2015-04-20 15:35 in Propeller 1
Hi,

I've got a CNC stepper driver program written in assembly language, which is meant to run two stepper motor axii from each COG for up to 10 axii simultaneously on 5 Cogs. These cogs are meant to be slaves of a C program (a master spooler program) which feeds motion vectors to them.
Since I'm trying to port this from another muti-processor platform, I don't know SPIN and don't really want to learn and rewrite my program in Spin if I can avoid it -- especially since I already have the main program in C, and spin is very *slow* compared to assembly language for timing critical operations.

Catalina seems to allow me to load assembly programs into a cog using a _coginit( (int)data_structure>>2, (int)code>>2 ); call, but there is no documentation on how to generate a PASM binary from assembly code that originates correctly at address 0, and resolves relative symbols within the aseembly language module without confusing them with global C varaibles, etc. Rather Catalina's demos show an example where someone had the code already written to an array like: unsigned long code[] = { 0x68ffec01, 0x64ffe801, ... }; which means a miraculous step was omitted where an assembler someplace generated those numbers ... which means I need an assembler ... but I don't see any stand alone assembler anywhere in Catalina or propeller-gcc (EDIT: yes! propeller-elf-as exists--but no docs...), or documentation for one, and nothing obvious in prop-gcc learner modules, either.

So: How can I create a the binary pattern/array for a stand alone, independent assembly language program, which can be loaded into a cog by a C program but whose addresses and labels are NOT part of the C program, and does not run on the C core ?

if I were to try using *inline* assembly, say in a C function, or use the prop-gcc run_cog() command, then the assembly language, as far as I can tell, would be running on the C core -- and not independently. eg: The C compiler would want to link the local inline assembly variables to the main C program, and Jump addresses would likely be wrong as they would be in hub memory -- and it's not really a hand written and independent assembly lanugague program anymore, meant to run by iteself in a COG but something being run on the C interpreter/loader core.

The program I want to run has an extremely simple interface where the 'par' register points to a C structure (in hub ram) of three longs and that *alone* is the complete interface through which all information comes to the slave Cogs from the main program/spooler: eg:

typedef struct { long command; long data; long synchronizeStatus; } stepper_interface;
stepper_interface queue[5];

So, what I want is to be able to do something like: _coginit( (&queue[0]) >>2, (&my_program_is_here)>>2 ); and my program will automatically link itself to the main C prorgam through the data structure called queue.

But I don't know how to covert an assembly language program into a byte stream called 'my_program_is_here' that I can embed portably in a C program.

To be very clear, here is a skeleton outline of the assembly language slave program I need to load into cog ram and execute:

DAT           org         '' Assembly routine to output quadratures or step & direction pulses.

begin         rdlong    temp,par                '' Initialize prescalar offsets from 'Command' member.
              neg       temp,temp               ''
              add       temp,#28                ''

              movs      PS0,temp                '' Hardcode prescalar offsets in self modifying code.
              add       temp,#2                 ''
              movs      PS1,temp                ''

              mov       dataMem, par            '' Precompute Data & Sync member pointers.
              add       dataMem, #4             '' data=&par[1]
              mov       syncMem, par            ''
              add       syncMem, #8             '' sync=&par[2]
              
              rdlong    outputPin,dataMem       '' setup outputs for step/direction/quadratures
              mov       temp,#3                 ''     
              shl       temp, outputPin         ''
              mov       dira, temp              ''

              wrlong    inSync, syncMem         '' Write the zeroed sync in mem.                                        
              neg       outputPin,outputPin     '' Compute backshift outputPin
              add       outputPin,#28           ''

              waitpeq   firstTrig, firstTrig    '' Indicate cog awaits init.
              mov       inSync, inSyncStart     '' NotRunning + cleared Qs.
              jmp       #Axis0                  '' Begin operations.

firstTrig     long      2

'' ------ CONSTANTS -----
sgnExt        long      $FFFFFFFF
axis0R        long      $01000000 '' Axis0 is Runable.
axis1R        long      $02000000 '' Axis1 is Runable.
axis0U        long      $00000007 '' Axis0 is Usable mask.
axis1U        long      $00000700 '' Axis1 is Usable mask. 

inSyncStart   long      $FCFFFFFF '' not running, but now in use constant.
combMask      long      $50000000
PSM0          long      $30000000
PSM1          long      $C0000000



{{ Lots of assembly language to do encoder/step direction counts goes here }}

PS0           shl       temp, #28               ''19
              and       temp, PSM0              ''20

{{ lots more code would go here... but omitted....}}

'' --------------------------------------------------------- END OF TRAJECTORY LOOP
'' Totaly zero data-block; these are state variables, local to the COG.

axis0Tn       long      0       ''Reg 0 Time of next motion
axis0An       long      0       ''Reg 1 Acceleration of next motion
axis0Vn       long      0       ''Reg 2 Velocity of next motion
axis0PH       long      0       ''Reg 3 Position of next motion
axis0T        long      0       ''Reg 4 Presently executing motion's Time.
axis0A        long      0       ''... Acceleration
axis0VL       long      0       ''... Velocity
axis0PL       long      0       ''... Position

axis1Tn       long      0       " Same as above, but for second axis....
axis1An       long      0               
axis1Vn       long      0
axis1PH       long      0
axis1T        long      0
axis1A        long      0
axis1VL       long      0
axis1PL       long      0

triggerX      long      0       '' Reg16  Simultaneous trigger of all axii.
unSync        long      0       '' Reg17  Force the sync to use these.
axisEN        long      0       '' Reg18  Enable axii beyond 1 cycle.
inSync        long      0       '' Reg19  tracking data for what is queued.

temp          long      0       '' Reg20
outputPin     long      0       '' Reg21  output pin offset.
combine       long      0       '' Reg22  Where to combine outputs for the axii.

axis0VH       long      0       '' Reg23  sign extension for velocity.
axis1VH       long      0       '' Reg24

register      long      0       '' Reg25
dataMem       long      0       '' Reg26
syncMem       long      0       '' Reg27

How can I turn a program like that one into an array of longs using either the tools in propeller-gcc, or in catalina ?
«1

Comments

  • SRLMSRLM Posts: 5,045
    edited 2015-04-06 21:49
    I have a couple of examples of using an assembly cog with PropGCC, and having a shared data structure accessible to both the assembly program and the C++ code:

    With .S assembly files:
    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/pulsewidthreader
    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/pwm2
    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/quadrature_encoder
    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/serial

    With binary blobs:
    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/pwm32
    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/sd

    With inline assembly:
    https://github.com/libpropeller/libpropeller/blob/master/libpropeller/i2c/i2c_base.h

    The assembly is assembled during the makefile, and PropGCC automagically creates a global variable called `_load_start_XXXX_cog`, based on the following line at the beginning of your .S file:
    .section .XXXX.cog, "ax"
    

    In your C/C++ code, you can then do:
    extern char _load_start_XXXX_cog[];
    ...
    
    cognew(_load_start_XXXX_cog, &someVariable);
    
    

    The `someVariable` is your shared memory (mailbox) for communication.

    For assembling and compiling the whole business, I like to just throw all my .cpp, .h, and .S files at propeller-elf-g++ and let it sort it out (with the --Wl,--gc-sections flag to optimize) rather than dealing with a real Makefile. You can see that approach here.

    Alternatively, you can pre-assembly the assembly and include that directly as a binary blob. I don't really like doing that, although I have on a couple of occasions (I think there was some issue with having the assembly out for those? I don't recall).

    Inline assembly can also be a good choice if you don't really want to dedicate a whole cog to the task, and your "master" cog will be blocking on the slave cog anyways. In that case you might as well run the I/O in your master for which assembly is a good choice. I2C is an example. In the inline assembly code linked above, note that it runs in the cog natively, with no PropGCC stuff in the way (via forced FCACHE). That little piece of code is what I'm most proud of out of the entire libpropeller code base.
  • Cluso99Cluso99 Posts: 18,069
    edited 2015-04-06 23:21
    Catalina can do what you require because I have done it. But that was quite a while ago, so I need to dig it out.
    There are examples (look for plugins IRC) in the latest Catalina.

    Does Catalina compile your C program? Are there interrupts in your C program (because the propeller doesn't have interrupts)?

    Of course there is now also PropGCC but I haven't used it so cannot help you here.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-07 08:51
    SRLM's comments above are great, and I only have one tiny snippet to add:

    By someone else's recommendation, I created a function at the bottom of my assembly file which does the cognew for me. I like this solution a little more than the alternative because the C file depends on an symbol whose name is explicitly defined rather than a file name. It also ensures the assembly file gets linked in and you don't find yourself fighting linker issues down the road.

    https://github.com/DavidZemon/PropWare/blob/release-2.0/PropWare/spi_as.S#L526
  • FastrobotFastrobot Posts: 51
    edited 2015-04-07 14:50
    Cluso99 wrote: »
    Catalina can do what you require because I have done it. But that was quite a while ago, so I need to dig it out.
    There are examples (look for plugins IRC) in the latest Catalina.

    I began looking at plugins, although that's a farily complicated system that requires the use of SPIN to register it, etc. I would rather not use something so proprietary if I can avoid it. Catalina is able to do inline assembly, so it *should* be able to create cog code in a manner similar to the inline example shown for PROP-gcc in SLRM's post. The problems are going to be associated with linker issues and compression (if any); eg: if there a possibility of multiple BSS sections, or of symbols from different inline assembly code being resolved to a single address when multiple separate addresses are intended (local vs. global variables.) then these collisions are what I am concerned about screwing things up.
    Does Catalina compile your C program? Are there interrupts in your C program (because the propeller doesn't have interrupts)?

    Yes, Catalina compiles the C portion of it just fine. There are no interrupts, and never were. The code originally ran on microchip 8 bit processors without any interrupts, mulitplies, etc. It's just going to be far more efficient, faster, and cost effective to run on a single propeller chip rather than 12 microchip MCU's with all the wiring between them. I get 10 axii / propeller + a PLC to boot for less cost. I just have to re-write the assembly language code for the trajectory execution (basically cycle counting, and position delta's addition...) into propeller assembly, which isn't hard for such a simple program.
    Of course there is now also PropGCC but I haven't used it so cannot help you here.

    Both propeller gcc and Catalina have problems, although the PropGCC is showing promise at being a more robust solution at the moment, having less show stopper bugs; but mostly its' just documentation issues that are making it hard to figure out how to get this working on either system.

    I like Catalina quite a bit; for Catalina can be run from any directory on my linux machine, so I can happily place it on a memory key and take it with me from place to place, esp; if I am talking to professors at universities and don't have superuser privileges to install it on their machines with. Catalina will run from a user directory just by setting an environment variable. But ... Unfortunately, Ross hasn't got the latest version debugged for 64 bit linux's (See my post here http://forums.parallax.com/showthread.php/153750-Catalina-3.13.2-smaller-and-faster-better-IDE?p=1324802&viewfull=1#post1324802 ) -- so Catalina as hosted on Sourceforge can't download to QUICKSTART boards from a 64 bit linux machine right now.

    However, PropGCC is linux flavor dependent -- basically packaged for UBUNTU, and requiring to be installed in the /opt directory with root privileges. But I *REALLY* like to have my tools installed on a USB key in a generic way.... not on the system root. just FYI, and for others who may want to try PropGCC on many other flavors of Linux: I am able to install it on other versions of Linux -- just got a generic tar file for PropGCC from the Ubuntu .deb by manual extraction; eg: "ar -x simple-ide_1-0-1-rc1_amd64.deb ; tar -xf data.tar.gz"; and then I had to copy the system's libncurses.so.5 to the memory key where I untarred simple-ide, but with ncurses renamed as libtinfo.so.5, to be found with the environment variable LD_LIBRARY_PATH="/media/memory1/.local/opt/parallax/bin" all because PropGCC is linked against a nonstandard library name. But even with the LD_LIBRARY_PATH set, only the command line tools in opt/parallax/bin are usable. The graphical IDE is too dumb to figure out that it has been installed in a different directory than /opt, and will start up -- but not load a project, or compile anything; and nothing in the instructions shows how to set an environment variable to get it to work...

    Nothing short of building a changeroot environment (basically a bad idea for portability reasons) will allow PropGCC to be installed on a memory key that I can take from computer to computer at a university and use and share with friends. That's it's primary downfall... not portable.

    But, on the other hand -- the command line tools at least work, so I can take code compiled on Catalina and load it into a propeller using PropGCC's propeller-load program. Without that, I wouldn't be able to use Catalina or PropGCC -- so as I said, they both have problems.
  • FastrobotFastrobot Posts: 51
    edited 2015-04-07 14:55
    SRLM's comments above are great, and I only have one tiny snippet to add:

    By someone else's recommendation, I created a function at the bottom of my assembly file which does the cognew for me. I like this solution a little more than the alternative because the C file depends on an symbol whose name is explicitly defined rather than a file name. It also ensures the assembly file gets linked in and you don't find yourself fighting linker issues down the road.

    https://github.com/DavidZemon/PropWare/blob/release-2.0/PropWare/spi_as.S#L526

    Thanks David, that's a really good example of how to write a C function in assembly language to load the separate assembly language module but be inside the same .S file and be automatically linked together with no scripting glue or Makefile required....
    Very helpful!
    :)
  • FastrobotFastrobot Posts: 51
    edited 2015-04-07 17:27
    SRLM wrote: »
    I have a couple of examples of using an assembly cog with PropGCC, and having a shared data structure accessible to both the assembly program and the C++ code:

    Your examples are excellent.
    How did you make the binary blobs, though ?

    I figured out, last night, that I can compile a prorgam using ./propeller-elf-gcc -mcog -nostartfiles ${f}.S # create an a.out file.
    and then use readelf to get a hexdump of the .text section and turn it into a binary blob C file, using sed and grep to fix the byte order issues:
    #!/bin/bash
    # ScriptName:  asm2c.rc
    # Convert/compile an assembly language file into a C long value array.
    # Written by Andrew Robinson; April 7th, 2015 
    #
    set -x
    set -e
    f=${1%\.S}  # BASH trick to remove any .S on the end of file name; otherwise this will run in any shell...
    rm -f ${f}-S.c
    ./propeller-elf-gcc -mcog -nostartfiles ${f}.S  # Generate a.out
    # Convert a.out file's .text section into a C array of longs...
    if [[ -r a.out ]]; then
      echo "unsigned long ${f}_S[]={" > ${f}-S.c
      ./propeller-elf-readelf -x .text a.out\
         | grep -Poe "(?<=0x\S{8})(\s\S*){1,4}"\
         | sed -ne "s%\(\S\S\)\(\S\S\)\(\S\S\)\(\S\S\)%0x\4\3\2\1,%gp" >> ${f}-S.c
      echo "};" >> ${f}-S.c
    fi
    

    So, the script I wrote auto-generates a file changing the .S of the original assembly name to -S.c, so it can be used like: #include "myfile-S.c"
    I compile using gcc so that the macro-preprocessing (cpp) is available in my source code, and I see you can do the same with g++ if so desired, not that c vs c++ matters for an assembly language file....


    I think the .S file is probably the way to go, over using inline assembly, as Catalina and PropGcc use different ways of implementing the _asm_ directive ; but they both seem to accept propeller assembly in .S files OK.

    Is there a simpler way to automatically generate the blobs using command line tools included in PropGcc?
    I tried bin2c , but it converts the WHOLE file not just the .text section into a binary blob, and that's not a good idea....
  • David BetzDavid Betz Posts: 14,511
    edited 2015-04-07 17:43
    Fastrobot wrote: »
    I like Catalina quite a bit; for Catalina can be run from any directory on my linux machine, so I can happily place it on a memory key and take it with me from place to place, esp; if I am talking to professors at universities and don't have superuser privileges to install it on their machines with. Catalina will run from a user directory just by setting an environment variable.
    PropGCC will run from any directory as well as long as you put its bin directory in your path. We just install it to /opt/parallax by default.
  • Cluso99Cluso99 Posts: 18,069
    edited 2015-04-07 17:56
    Fastrobot,
    You are into Linux and C way more than me. We use Catalina for a 3prop professional solution although I only interfaced the spin/pasm section to the c section.

    Since you can compile both GCC and Catalina to do your job (but not Catalina on a 64bit linus machine), you might just be able to compile the C section as standalone.
    Then start your objects with spin and then load the compiled c program. You can do this with Catalina, so presume you can also do this with GCC.
  • SRLMSRLM Posts: 5,045
    edited 2015-04-07 18:11
    Fastrobot wrote: »
    Your examples are excellent.
    How did you make the binary blobs, though ?

    The binary blobs are from the original spin2cpp conversion of those objects. You could look there to see how it does the conversion. Like I said, I don't really like the binary blob solution but I haven't had a chance to update those objects and I included it for completeness. I much prefer to just toss the .S file to propeller-elf-g++ and let it deal with it.
  • FastrobotFastrobot Posts: 51
    edited 2015-04-07 23:17
    SRLM wrote: »
    The binary blobs are from the original spin2cpp conversion of those objects. You could look there to see how it does the conversion. Like I said, I don't really like the binary blob solution but I haven't had a chance to update those objects and I included it for completeness. I much prefer to just toss the .S file to propeller-elf-g++ and let it deal with it.

    mmm... I see. I agree -- the .S file is much nicer. It's easy to read, edit, and link by mere inclusion to GCC compile line, or Catalina's.

    The binary blob is just one way that I know is compatible between PropGcc and Catalina, so I wanted to know how to do it. Both systems have the ability to do either _coginit() or cognew() to launch arbitrary binaries into a cog after #include <propeller.h>, although the calling conventions differ I can use a few #defines, to make one source code file work on Catalina and PropGCC just fine.

    Catalina, now that I'm looking carefully -- has a program "spinc" -- which converts a spin objects to a "C' array binary blob, but when I check for a program called spin2c* or spin2cpp, in the PropGCC package, I don't find it; eg: I'm using simple-ide-1-0-1-rc1_amd64.deb -- so I guess making a binary blob via. spin2cpp is not going to be supported by default in the gcc tools.

    So -- I'll just keep my own script, then.

    On the other hand, The .S files, do have a few compatibility gotchas.... let's see if I can work through them:

    Catalina does accept .S files, but as far as I can tell -- they must be in PASM format, GAS format is not an option, and PASM doesn't accept .section, .compress, or fcache directives, or 0x hex prefixing. Worst of all, Catalina refuses to do C pre-processing on .S files passed to the C compiler. darn.
    So, to be more compatible -- I ought to write my assembly in pure PASM with no preprocessor macros.

    That brings up a question, will GCC compile PASM files flawlessly? David's example (SwimDude0614) above included an assembly language directive to indicate PASM was being used; eg: .pasm , but when I try adding that directive -- both Catalina and propeller-elf-gcc reject it as invalid.

    Is it no longer necessary ?
    I seem to be able to compile this just fine on either Catalina, or propeller-elf-gcc ; am I reasonably safe, or are there known issues I should be aware of?
    '' @file test.S
    '' This file is made to be compiled to an executable, and then the hex codes
    '' extracted to make a C variable upon which can be run coginit()
    
    '' for gnu-as, these are possible to uncomment, but they aren't compatible to both compilers:
    ''			.pasm  '' this directive does not work regardless of compiler....
    ''			.section test.cog, "ax"
    ''			.compress off
    ''	 		fcache #(cogEnd - cogStart) 
    
    test_S '' A label to mark where the linker was before the org 0 is compiled
    			org		0
    
    cogStart           
    			mov		__bss_start, #0
    			add		cogStart,#$100  '' Add 1 to bss clearing pointer
    			add		cogStart,#$100  '' ...
    			djnz		count, #cogStart
    
    			or		DIRA, LED_PIN
    			andn		OUTA, LED_PIN
    			mov		count,CNT
    			add		count,increment  '' prime the loop by making count > cnt
    loop
    			waitcnt		count,increment  '' wait cnt==count then count+=increment
    			xor		OUTA, LED_PIN
    			jmp		#loop
    
    variables
    
    count		long	__bss_end-__bss_start '' temp to clear BSS at cog. start
    increment	long	5000000
    LED_PIN		long	$30003
    
    '' for gnu as, we could do .section bss...
    
    __bss_start
    testing0		res		16	'' Reserve 16 bytes for BSS space, just to test.
    testing1		res		16
    __bss_end
    
    cogEnd	
    			fit		496
    

    Secondly, you used a fcache directive in your assembly language examples.
    I assume that is to force the entire image to be loaded into hub ram at once, or something, so as not to have a fragmented piece of code when loading from external eeprom/SD memory?
    And, the compress directive is intended to prevent automatic optimizations that can be decompressed by the C-core, but are not runnable directly on a propeller COG?

    Is there a way to compile a .S file into a .o file with command line switches to do the same things as those directives, or do I have to edit the file by hand each time I want to move it back and forth between Catalina and PropGcc?
  • SRLMSRLM Posts: 5,045
    edited 2015-04-08 04:31
    It looks like you're right: SimpleIDE doesn't include spin2cpp by default, which seems like an oversight to me. I think that raw PropGCC includes it by default, but I've always built from source and in any case @David Betz has been working on cleaning up and organizing the PropGCC repository with the GitHub move.

    With PASM, if it works at all it probably works just fine. You can always compare the binaries to be sure though. In regards to `.pasm`, there was some discussion about it's necessity and use. I forget what that resulted in, so I'll let someone else chime in on that.

    The fcache is a PropGCC feature to load up a block of assembly code from the hub to a cog, and run it there. It allows you to get native speed for code that's part of a larger LMM or CMM* program. I use it in the I2C examples so that the clock can run at 400kHz and the timing is as exact as possible, while still being "just a function" to calling C programs.

    * fcache is probably used in the XMM models, but I never use those so I'm not sure.

    Native assembly code that you launch with `cognew()` won't use fcache: it's only relevant for CMM, LMM, etc.

    The `.compress` directive is to make it the assembly work right when you're using CMM for the rest of your program.

    Most of the directive issues that you can use with PropGCC assembly has to do with figuring out what address to use (cog, hub, or program) in which situation. It can get a bit tricky trying to figure out where everything refers to. I don't think you can get around the directives.
  • ersmithersmith Posts: 5,931
    edited 2015-04-08 06:03
    Fastrobot wrote: »
    But even with the LD_LIBRARY_PATH set, only the command line tools in opt/parallax/bin are usable. The graphical IDE is too dumb to figure out that it has been installed in a different directory than /opt, and will start up -- but not load a project, or compile anything; and nothing in the instructions shows how to set an environment variable to get it to work...
    Sounds like this is a SimpleIDE bug. As you've discovered, PropGCC itself (i.e. the command line tools like propeller-elf-gcc) will work fine regardless of where they are installed. If you're comfortable with a command line, I'd suggest just ditching the IDE and running propeller-elf-gcc yourself.

    I'd also suggest getting a newer version of PropGCC than the one bundled with SimpleIDE. That one (the 1.0 release) is pretty ancient. The current default tree has a much better assembler that will accept PASM code (with either the .pasm directive or a -pasm command line option) instead of GAS syntax. The main difference is the handling of addresses: in GAS mode addresses are always byte addresses, even inside COG memory. This matters if you do arithmetic on labels: something like "foo+1" in PASM would have to be written as "foo+4" in GAS mode (but as I said the new gas does have a compatible PASM mode where "foo+1" works the same as in PASM). -pasm also tells the compiler to ignore Spin statements, so you can pretty much just feed it .spin files and get the assembled PASM code out.

    Eric
  • ersmithersmith Posts: 5,931
    edited 2015-04-08 06:12
    A few other notes:

    (1) The .pasm directive is for PropGCC 1.9 and later. In PropGCC 1.0 (the one included with SimpleIDE) there was a .cog_ram directive that was kind of similar but much more limited. You had to be very careful about any arithmetic on labels in the PropGCC 1.0 assembler -- basically I would suggest avoiding that. The new assembler allows you to use a -pasm command line option instead of the .pasm directive.

    (2) The .compress directive is for CMM mode. With .compress on the instructions are compressed, but have to be decompressed by the CMM kernel -- they cannot be directly executed by hardware. So in CMM mode you have to be careful to put ".compress off" in front of any code you plan to load in to a COG. If you're not using CMM you can omit the directives.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-08 06:20
    Fastrobot:

    I'd love your help testing this new build of PropGCC. Go here (click "log in as guest") and then download the artifact for PropGCC gcc4-linux-x64 (assuming you're on a 64-bit machine... I don't have 32-bit linux builds yet). That page will always have the most up-to-date and stable version of PropGCC
  • twm47099twm47099 Posts: 867
    edited 2015-04-08 07:51
    Fastrobot,
    Since you are using SimpleIDE, post 65 in the link below shows a way to include PASM code from a Spin object into a C program. So you could write a simple spin program that declares the variables in order that you want to transfer to the PASM and call the PASM cog, and have the PASM program in a dat block. Then call the PASM from the C program. The entire thread shows me being taught how to do this, along with my errors and successes.

    http://forums.parallax.com/showthread.php/157441-Can-SPI-in-Simple-Libraries-be-speeded-up/page4

    Post 22 in the link below is another example. Since only one array variable was transferred for each call to the PASM, it wasn't necessary to define a structure.

    http://forums.parallax.com/showthread.php/134106-Updated-17seg-LED-driver-for-PPDB-now-available./page2

    Hope this helps.
    Tom
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 00:33
    twm47099,

    Unfortunately the IDE portion of SImpleIDE does not work. I need to take David up on testing the next version of it...
    I looked at your examples, but I'm not sure how you made the binary blobs -- unless you mean, you made them with some button on the IDE, or it does it automatically.

    I have a method that works and is compatible with PropGCC and Catalina both, and so it should also work in the IDE.
    Perhaps you can tell me, if you have a working copy of the SIMPLE-IDE whether or not you can compile my example program.

    The major problem I've been encountering is that the Catalina preprocessor is somewhat broken, and I can't make automatic linkage macros that I can just type a name into and have it produce a header file -- rather I have to hand edit it for Catalina. I would love to have just used the method in post #2 of this thread, but unfortunately PropGCC makes variable names in excess of 16 characters -- which also causes spinnaker in Catalina to bomb out with undefined variable name errors. So the best I can do is a hybrid method that uses post#2's majic, but automatically store the hub load address in a shorter global variable name which both Catalina and PropGCC are happy with.

    I'm open to suggestions on how to make this cleaner... but at least it works.
    There are three files, a compatibility header: "gcc2catalina.h", an assembly language driver to run on a cog, and a C program to load the driver.
    File names are listed at the start of each code snippet.
    //gcc2catalina.h
    //Compatability header for catalina, to allow it to work with the same
    //source code as PropGCC for my demo program.
    
    #ifdef __CATALINA__
    #include <catalina_cog.h>
    #define cognew( code , data ) _coginit( ((long)(data))>>2, ((long)(&code))>>2, ANY_COG )
    #define cogid() _cogid()
    #define cogstop(id) _cogstop(id)
    #define waitcnt(count) _waitcnt(count)
    #endif
    
    ' test.S
    ' A demonstration program for QUICKSTART that turns on two blue LEDS.
    ' It's designed to compile either on Catalina or PropGCC
    ' and link to a C program as the variable test_S.
    ' Note: Because of linker issues, I store the address of the hub ram
    ' in the variable test_S, as there is no portable way to get the start
    ' address of a section which can be relocated -- except to use the linker.
    
    '-------------------------------------------------------------------------------
    ' Store address of test.S's hub ram binary in a C variable called, test_S
    
    #ifdef __GNUC__  
                ' note: gcc/C requires mangled names with extra _ prefixed for linker
                .global __load_start_test_cog 
                .global _test_S 
    _test_S     long    __load_start_test_cog
                .section .test.cog , "ax"
                .compress off
    '           .pasm       ' doesn't work in simple ide 1.0
    '           fcache #( _end - _start ) ' doesn't work in simple ide 1.0
    #else
    DAT ' code segment
    ' Catalina Export test_S  <- this comment is acutally a binder directive
    C_test_S_ ' place holder in hub ram.
    #endif
    
    '------------------------------------------------------------------------------
    ' All remaining labels in this file are local scope, only.
    ' They won't link with any other module's labels.
    ' -----------------------------------------------------------------------------
                    org     0
    _start          or      DIRA, led_pin
                    or      OUTA, led_pin
    halt            jmp     halt
    led_pin         long    $30003
                    fit     496
    _end
    
    #include <propeller.h>
    #include "gcc2catalina.h"
    extern void* test_S;
    int main(void) {
            DIRA=0x70007;
            OUTA=0x10001;
            if ( cognew( test_S , 0 ) < 0 ) OUTA=0x70007;
            if ( (int)test_S & 0x03) OUTA=0x20002;
            waitcnt( CLKFREQ*2 + CNT );
            cogstop( cogid() );
            return 0;
    }
    

    From the command line, it compiles and runs by one of two ways:

    . use_catalina
    catalina test.S stest.c -lc
    payload -z -t 1000 test

    Or using PropGCC from the command line:

    propeller-elf-gcc test.S stest.c
    propeller-load -r a.out

    I'm not sure how to do it in an IDE. :)
  • twm47099twm47099 Posts: 867
    edited 2015-04-09 07:12
    Fastrobot,
    I am posting from an Android tablet, so I'm not able to test your code.

    I apologize that the code shown in post 65 did not have everything needed to show how my code works.
    The binary blob is made and loaded from a Spin file that is added to the SimpleIDE project. All my code showed was the PASM part of the spin file. A full copy of the modified spin object is in libspipasm v2.zip in post 70 of that thread. The file name is xSPIAsm.spin. That file should be added in "project" view to the project (left hand window).

    The C program and SimpleIDE does not use the spin part of the program, but loads (assembles?) the PASM code into a cog using the lines:
    spia_t *spipasm_start(int clkd, int clks) 
    { 
    spia_t *device;               // Declare spipasm pointer 
    device = (void *) malloc(sizeof(spia_t));             // Allocate memory for it 
    if(device->cog == 0) 
      { 
        device->command = 0;            // pasm stays in waiting loop till non zero 
        extern int binary_xSPIAsm_dat_start[]; 
        device->cog = 1 + cognew((void*)binary_xSPIAsm_dat_start, (void*)device);
       }
    

    The structure that is declared before main () contains the variables for the PASM in the order they are needed (which was originally established in the spin object). When I wrote the C code my intent was to just use a preexisting spin/PASM object as a black box. The original spin object comes from the library that is provided with the proptool. I did have to slightly modify the PASM because the initialization parameters (clockstate and clockdelay) were assigned in the spin portion of the object which couldn't be used in the C program.

    Tom
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 10:28
    Fastrobot:

    I'd love your help testing this new build of PropGCC. Go here (click "log in as guest") and then download the artifact for PropGCC gcc4-linux-x64 (assuming you're on a 64-bit machine... I don't have 32-bit linux builds yet). That page will always have the most up-to-date and stable version of PropGCC

    Oh, I see ! :) So -- PropGCC is actually a separate project from SimpleIDE and you have builds for the GCC portion.... Up until now, I was thinking that as they were packaged together in the simple-ide release that it was all one code base... but I need to upgrade parts of the package separately. OK.

    So, Basically, PropGCC command line tools can run from a USB key -- it's just the GUI/IDE which seems to be hardcoded to run properly only from root install.
    I notice, in the package I have now -- simple-IDE-1.0.1's "propeller-load -r -g " GDB command doesn't work (doesn't recognize -g); so is the flag working in the package you list as gcc 4 -- ? or do I need to get the gcc 5 release ?

    Also, one other question -- the linker auto-generates a variable _load_start_XXXX_cog , but of course, that symbol isn't available at the time the assembler is generating objects. So, I had to use a linker trick to shorten the linker name for compatibility with Catalina; but I'd like to add a line to the linker script so as to auto-generate a shorter name automagically... but when I did a search for linker scripts with find . -iname '*.ld" I came up blank. Where does PropGCC keep the default GNU linker scripts for the targets, and how are they named ?

    and one other bit of feedback... as a linux user, I tend to type pr [tab] in order to get linux autocomplete to do the compiler type as quickly as possible, I expect it to produce propeller-elf- and then I finish by typing gcc or nm or whatever.... So: It's a bit of a pain to have an inconsistent name, eg: propeller-loader in the same directory, as that stops autocomplete early and requires extra typing for all tools which are used more often than the loader.... propeller-load is still an elf binary system, even if it loads other binary types as well. It would be more convenient to have it also named propeller-elf-load ; is there a particular reason it isn't named that way ?
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-09 11:47
    Fastrobot wrote: »
    Oh, I see ! :) So -- PropGCC is actually a separate project from SimpleIDE and you have builds for that portion.... Up until now, I was thinking that as they were packaged together in the simple-ide release that it was all one code base... but I need to upgrade parts of the package separately. OK.

    So, Basically, PropGCC command line tools can run from a USB key -- it's just the IDE which seems to be hardcoded to run properly only from root install.
    The simple-IDE package's propeller-load -r -g command doesn't work for GDB (doesn't recognize -g); so is it working in package you list with gcc 4 -- ? or do I need to get the gcc 5 release ?

    Now you got it :)

    As for gdb, that must be run separately. Here's what I use for running GDB (not that I do it very often, as it is only moderately helpful)
    propeller-load -bQUICKSTART MyProject.elf -r -g && propeller-elf-gdb MyProject.elf
    
    Taken from here
  • David BetzDavid Betz Posts: 14,511
    edited 2015-04-09 11:58
    Now you got it :)

    As for gdb, that must be run separately. Here's what I use for running GDB (not that I do it very often, as it is only moderately helpful)
    propeller-load -bQUICKSTART MyProject.elf -r -g && propeller-elf-gdb MyProject.elf
    
    Taken from here
    However, I'm not currently building gdb or gdbstub for the propeller-gcc repository. I'll look into adding that soon. To be honest, I didn't realize anyone was actually using gdb! :-)
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 13:59
    Hmm... In the simple IDE 1.0.1, they have the propeller-elf-gdb, and the stub -- but their version of propeller-load does not support -g !!!
    You on the other hand, have a version which supports -g , but no gdb executable. :) It's like dutch doors, half way -- either way. :D

    I'm trying out the gcc 4 version from your repository.
    The tools you do have for x86_64 appear to be working fine, although I still can't find any gcc/ld default linker scripts.... weird.
    Just as a note, though, I have multilib installed so I can do 32 and 64 bit binaries, so my test won't catch things that require a 64 bit clean environment.
    I just installed BTRFS, though, so I can do a snapshot of my stystem and uninstall all 32 bit compatability stuff later this week on the backup snapshot -- eg: to make sure it fully works for 64 bit only systems. I'm absolutely loving linux kernel version 3.18.9 ! Lots of bug fixes, and a union file system built in without needing to patch the kernel. YAY!

    I wonder if I can take the PROP_IDE1.0.1 executable for GDB and run it with your executable for propeller-load....
    We'll know in a few minutes.....
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-09 14:22
    I would think it would work on a 64-bit only machine, but I'm glad you're testing it since that's not something I ever would have thought to check. It is built on a 64-bit machine for a 64-bit machine, so I can't imagine what 32-bit stuff it would try to reference. I just have no idea how to build for 32-bit linux machines yet :/

    David - the 32-bit Linux issue probably needs to be addressed in the propgcc thread some day. I'm not too worried at the moment though since all my stuff is 64-bit :P
  • David BetzDavid Betz Posts: 14,511
    edited 2015-04-09 14:25
    I would think it would work on a 64-bit only machine, but I'm glad you're testing it since that's not something I ever would have thought to check. It is built on a 64-bit machine for a 64-bit machine, so I can't imagine what 32-bit stuff it would try to reference. I just have no idea how to build for 32-bit linux machines yet :/

    David - the 32-bit Linux issue probably needs to be addressed in the propgcc thread some day. I'm not too worried at the moment though since all my stuff is 64-bit :P
    Ugh. I'm not sure I can take on that sort of testing. I think if Parallax wants to support PropGCC on all of these platforms they'll have to do it themselves. Sorry.
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 14:56
    I would think it would work on a 64-bit only machine, but I'm glad you're testing it since that's not something I ever would have thought to check. It is built on a 64-bit machine for a 64-bit machine, so I can't imagine what 32-bit stuff it would try to reference. I just have no idea how to build for 32-bit linux machines yet :/

    David - the 32-bit Linux issue probably needs to be addressed in the propgcc thread some day. I'm not too worried at the moment though since all my stuff is 64-bit :P

    I have a special install script program that takes the slackware 64 bit and 32 bit distributions, and runs a diff on each file in the packages. It then removes all duplicate files, and any files (eg: binaries) which are in the same directory but conflict in elf size, so the 32 bit version gets moved to a /32 subdirectory.

    Pretty much, I install linux twice on the same hard drive but save space by deleting all duplicate files. Since linux installs 64 bit binaries in /usr/lib64 and 32 bit binaries in /lib -- there's no conflicts in libraries, and any programs which expect 32 or 64 bit libraries find them exactly where they ought to. So, I can run 64 bit or 32 bit binaries on the same system with little or no problem, but if I want to single out 32 bit executables for system tools -- I have to change the path that I search for executables in. Slackware comes with a multilib capable version of GCC, so If I Set a few enviornment variables, eg: a path script found in Slackware in /etc/profile.d/32dev.sh -- that tells gcc where to look for 32 bit files instead of 64, then wallah... everything compiles 32 bit instead of 64 bit. It's not too hard -- just confusing at first.
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 15:14
    David Betz wrote: »
    Ugh. I'm not sure I can take on that sort of testing. I think if Parallax wants to support PropGCC on all of these platforms they'll have to do it themselves. Sorry.

    :D

    He's already testing it for you on a 64 bit clean machine, so I really don't need to. :)
    As long as you don't hardcode the paths, I'm happy to test and work my system around to suit the binaries available.

    About the program GDB, It does run -- but doesn't communicate with the propeller. I copied over both propeller-elf-gdb and gdbstubs.
    After GDB starts, When I tell it to 'run' it doesn't know the target. No error messages appear.
    So GDB needs some kind of initialization file somewhere that I don't see a copy of. The site you mentioned doesn't seem to show an init file anywhere obvious on that page...

    Normally, a system being debugged by GDB over a serial line or a TCP/IP connection runs a monitor program on the embedded device, and then GCC talks to it by using the target command, eg: "target remote 127.0.0.1:3000" or perhaps "target /det/ttyUSB0". I tried the latter one, as that's where the propeller is located -- compiling the last example program from a few posts back as: propeller-elf-gcc test.S stest.c -g
    When I loaded it, I was told it was "patching for debug at offset 0x774" so, it's primed for debugging -- but when I tried "target /dev/ttyUSB0" GDB complained that it received:
    Ignoring packet error, continuing...
    warning: unrecognized item "timeout" in "qSupported" response
    

    NOTE: Your tools happily produce -g and even -ggdb3 files, but the propeller loader only recognizes the -g file, otherwise it produces an "error: unable to debug this ELF file: __ccr__ symbol missing"

    So, we're close -- but there seems to be a problem in the communications target of gdb and I don't know what target protocol to tell gdb to use.

    Edit: AHA! Perhaps it's a pipe to a communications program?
    target remote |gdbstub

    It seems to work, but for some reason it 'starts' at the exit() function ?!
    That's not good...! I can't debug anything beginning from exit() !! :D
    bash-4.2$ propeller-load -bQUICKSTART -g -r a.out && propeller-elf-gdb a.out
    Propeller Version 1 on /dev/ttyUSB0
    patching for debug at offset 0x774
    Loading a.out to hub memory
    3260 bytes sent                  
    Verifying RAM ... OK
    GNU gdb (GDB) 7.3.1
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=propeller-elf".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /media/memoryb1/mysource/a.out...done.
    (gdb) break main
    Breakpoint 1 at 0x104: file stest.c, line 5.
    (gdb) target |gdbstub
    Undefined target command: "|gdbstub".  Try "help target".
    (gdb) target remote |gdbstub
    Remote debugging using |gdbstub
    0x0000026c in _exit ()
    (gdb) 
    
  • David BetzDavid Betz Posts: 14,511
    edited 2015-04-09 15:54
    Fastrobot wrote: »
    :NOTE: Your tools happily produce -g and even -ggdb3 files, but the propeller loader only recognizes the -g file, otherwise it produces an "error: unable to debug this ELF file: __ccr__ symbol missing"
    I guess propeller-load should be rewritten to use bfd to read elf files rather than including its own elf reader. That way it would probably work with -ggdb3 files as well. Care to take on that project? :-)
  • ersmithersmith Posts: 5,931
    edited 2015-04-09 16:24
    I see you figured out the "target remote |gdbstub" already. You probably have a working setup now; try
    b main
    c
    
    to see if it will break at main. Don't worry about the message saying it was stopped in "_exit"; it's actually stopped inside the LMM kernel, but gdb is confused by the symbols in internal COG memory having addresses similar to those in hub RAM.
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 16:46
    ersmith wrote: »
    I see you figured out the "target remote |gdbstub" already. You probably have a working setup now; try
    b main
    c
    
    to see if it will break at main. Don't worry about the message saying it was stopped in "_exit"; it's actually stopped inside the LMM kernel, but gdb is confused by the symbols in internal COG memory having addresses similar to those in hub RAM.

    nope... although I do understand about the hub ram vs. processor ram confusion. When I did object dumps to see how my code was linked... it would give kernel symbols for addresses below 496*4...
    This is what continuing makes happen:
    0x0000026c in _exit ()
    (gdb) disassemble
    Dump of assembler code for function _exit:
       0x00000264 <+0>:                     cogid   0x4 <__clkmode> 
       0x00000268 <+4>:                     cogstop 0x4 <__clkmode> 
    => 0x0000026c <+8>:                     nop
    End of assembler dump.
    (gdb) b main
    Note: breakpoint 1 also set at pc 0x104.
    Breakpoint 2 at 0x104: file stest.c, line 5.
    (gdb) c
    Continuing.
    warning: Remote failure reply: E01
    Ignoring packet error, continuing...
    Remote 'g' packet reply is of odd length: E01
    (gdb) 
    
    

    And I did it a second time, after freshly propeller-loading the file again, and without doing a break before setting the target.
    bash-4.2$ propeller-load -bQUICKSTART -g -r a.out && propeller-elf-gdb a.out
    Propeller Version 1 on /dev/ttyUSB0
    patching for debug at offset 0x774
    Loading a.out to hub memory
    3260 bytes sent                  
    Verifying RAM ... OK
    GNU gdb (GDB) 7.3.1
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=propeller-elf".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /media/memoryb1/mysource/a.out...done.
    (gdb) target remote |gdbstub 
    Remote debugging using |gdbstub
    0x0000026c in _exit ()
    (gdb) b main
    Breakpoint 1 at 0x104: file stest.c, line 5.
    (gdb) c
    Continuing.
    warning: Remote failure reply: E01
    Ignoring packet error, continuing...
    Remote 'g' packet reply is of odd length: E01
    (gdb) 
    

    Whatever is wrong, at least it is *very* repeatable.

    I'm also not quite sure what is going on with the gdb disassembler. That code looks suspiciously like exit code to me... but when I do an propeller-elf-objdump -d a.out | less
    I can't find that fragment of code anywhere in the program.
    What is GDB actually dissasembling?, and what is the breakpoint address ? that of execution in hub ram or cog ram ?
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 18:34
    jazzed wrote: »
    Hi.

    No one has ever officially released gdb for propeller. The default branch where it is known to work for some has never been officially tested or released.

    SimpleIDE includes gdb from the release_1_0 branch only because it is an output of the build process. The SimpleIDE manual (which is our reference for SimpleIDE whether anyone else reads it or not) makes no mention whatsoever of gdb support.

    There is a plan for a default branch test program for integrating with SimpleIDE in someone's head at Parallax ... some day it may spill out into a real project.

    :)

    Well, I don't think GDB is the problem here. By inspection, I can tell it's disassembling hub ram just fine, and able to find registers and change the PC, too.
    There's a small blob of nonzero memory in the first 0x278 addresses, that's roughly 632 bytes. Then it's all zeroes until addres 0x8000 -- which is where the parallax propeller Character ROM, etc. area starts. That tells me right away, when my .nocompress program bytes can't be found anywhere in memory, but the character shapes CAN be found -- that the propeller-loader is malfunctioning, not GDB.

    propeller-load says that it's downloaded 3260 bytes, and patched at 0x774 -- but that much information is not present in memory.
    Hence, I'm pretty sure that the monitor program loaded -- and the rest did not, or else it was erased and replaced by the monitor program.

    I am not sure how the monitor runs, but -- basically -- if the monitor program is running in a COG, by itself, I should be able to erase hub ram without crashing GDB. When I type, "load a.out" in GDB -- it says it downloaded the code into ram, and the monitor does not crash -- so far, so good... and when I do a dis-assembly, I now find the code matches what "propeller-elf-objdump -d a.out" says it should be. SO -- the problem isn't GDB. The problem was expecting propeller-load to load the program AND the debugger monitor together. It doesn't.

    Now, the question is -- what was propeller loader trying to patch, and what can and can't be done with the monitor program as it is...
  • FastrobotFastrobot Posts: 51
    edited 2015-04-09 19:49
    David Betz wrote: »
    I guess propeller-load should be rewritten to use bfd to read elf files rather than including its own elf reader. That way it would probably work with -ggdb3 files as well. Care to take on that project? :-)

    :) Oooohh.... that sounds like it might be a bit of large project at the moment, and maybe un-necessary work...
    eg: GDB already understands all elf versions, and is capable of loading a program in to the propeller using the monitor program by itself.
    So, if I want to use ggdb3 -- I should be able to load a dummy program with -g compiled on it, and then use gdb to re-load my actual program compiled with ggdb3. There's no reason to load ggdb files except when debuggging -- so it's not really a problem to do it through gdb anyhow. Almost everything can be done in an automated way with a gdb startup script...

    What, exactly, is the the loader trying to "patch", anyway? If there is source code for it, then I think it might be something that we could more easily accomplish by simply calling the gnu tools linker, ld,during compile time, to add it to the program. eg: it's not uncommon to have debug libraries on modern computers, so -- it shouldn't be strange to be able to link in a debug "C" kernel if necessary.

    Are there documents you might point me at, showing what exists of the gdb debugger monitor program ?
    It might be something I could do in a matter of hours, if it can be done with the normal compiler and linker tools....
Sign In or Register to comment.