Getting started with P1 and how to code

2»

Comments

  • AribaAriba Posts: 2,370
    edited 2016-01-06 - 08:01:58
    The big problem with C on the Propeller is that it allows to use standard libs and stdio like on a PC. And that Propeller users think that is the poper way.
    Nobody would do that on Microcontrollers like small PICs and others. I never seen an example for an AVR that uses printf.

    If you program in C, like in Spin, with optimized functions for the Propeller then C is often superior to Spin.

    If I make a small serial-out and decimal-out routine in C, I get these results for the Fifo(26) on an Activity Board:
    Model  time      size          without VM
    
    CMM:  4242 ms    2728 Bytes ( - 2436 = 292)
    LMM:  746 ms     3096 Bytes ( - 2576 = 520)
    
    I'm not sure if the VM size is correct, I have found it by just compiling an empty main() function. - Be aware that also Spin needs a 2048 Bytes VM, it just not shows in the size because it's loaded from ROM.

    The used C file is attached. (BTW: It uses only one cog, Spin needs a second for fast Serial)

    Andy
    c
    c
    988B
  • PropBasic does CMM.
    PropBasic does LMM.
    PropBasic can do a mixture of the above.
    PropBasic generates (or directly translates to) PASM. No overhead, no dependencies.

    The downside? It has b-a-s-i-c in its name.
    Should have named it ORPASM.
  • @Ariba, your code does run slightly faster. It shouldn't matter whether stdio is used or fdserial, but it does for some reason. The optimizer must be able to tweak your code better than mine for some reason. I'd have to look at the generated assembly to see what it's doing.

    @Mickster, I believe PropBASIC supports COG and LMM modes. I don't think it has a CMM mode.
  • Dave

    I have removed the 'unsigned' before int. Perhaps signed math is faster or better optimizable.

    Andy
  • cybersack wrote: »
    DavidZemon wrote: »
    You're gonna love PropWare
    PropWare sounds like a library I would be very comfortable with since I tend to think in Types (Data and Function) and generally appreciate being able to compile them with a discrete API.

    But, the reason I am here is to try and build some hardware to do some things in the real world with the Parallax, and so I have the obvious thought that the manufacturer's Spin/C is a more natural approach ?

    I am guessing that PropWare, in addition to encapsulating meaningful APIs, also takes care to the data I/O (i.e. aggregating the data and function features for a component), and also persistence across power on/off ?
    Does it do that ?

    David, I have 4 further questions:
    [1] Can I easily mix and match C/Spin/PropWare ?
    I ask this because I may develop a module in one language and then, learning a more facile approach, swap to another language.
    Does PropWare support C/Spin, and can C/Spin understand a PropWare library interface ?

    [2] Does the PropWare library give me the API to
    * perform AWG and push said (sine or compound) signal to an output pin (waveform generation in the 1 Hz -> 2 KHz range
    * perform Singnal Analysis and subsequent Spectrum Analysis ?
    such items would allow me to get past writing primitives-based code, and those classes tend to have specific APIs

    [3] Does PropWare give me some advantage with programming peripherals ?

    [4] Do I need to care about interrupts at all with PropWare (of course, I definitely do not want to go there)

    Thanks to all of you guys with loads of experience and have made the time to share your opinions and thoughts.

    Let me start by clarifying that PropWare has two components to it:

    1) HAL
    2) Build system

    HAL
    The HAL (hardware abstraction language) is a suite of classes to handle various peripheral functions. Inside that suite are classes such as PropWare::Pin, PropWare::Port, PropWare::FatFS, PropWare::UART, etc. There are few (very few) utility classes that are not hardware specific, such as PropWare::Queue. PropWare::Utility also contains some helpful functions, most of which are not hardware specific.

    Along with the PropWare namespace, a PropWare installation includes the libpropeller namespace (C++ HAL written by forum member SRLM) and the Simple libraries (C HAL written by Parallax). This means you don't have to dig through the Learn folder to find the specific files in the Simple libraries used by your project and copy them into your project directory if you ever switch from SimpleIDE to PropWare.

    To answer #2, yes and no. If you want a PWM signal (square) sure. libpropeller::PWM2 and libpropeller::PWM32 will work great for you. If you an anologue signal, no. I'm afraid I haven't written a DAC peripheral yet. I would be more than happy to whip one up for you, since most DACs have a very simple communication protocol over either I2C or SPI, both of which have classes in the PropWare namespace.

    I think i've answered #3 by now, but if you're still in doubt, YES :D

    Build System
    Equally as cool as the HAL is the build system. Written in CMake, it allows you to quickly build, link, and load a variety of languages for the Propeller. Currently it supports: assembly, C, C++, cogc, cogcpp, ecogc, ecogcpp, dat, and Spin. Now, before you get too excited about Spin, it's very limited at the moment: it will only extract the "DAT" section of a Spin file and then compile the resulting assembly as a binary blob. This is helpful if someone writes a driver in assembly (like FullDuplexSerial) and you want to invoke that driver from C/C++.

    You are on your own, however, to re-write the interface for that driver, which previously existed in Spin. But that isn't as scary as it sounds for a few reasons.
    1) Spin2cpp is really cool program written by another forum user (and shipped with PropWare) which will convert your entire Spin file into C++. I intend to eventually support this feature as a language option in PropWare, but have not done so yet. If you want to take advantage of it, simply convert the spin file manually by typing something like "spin2cpp MySpinFile.cpp -o MyCppFile.cpp" (full disclosure: I have no idea what the syntax is :) ) and then adding MyCppFile.cpp to your project.
    2) Even if you hand-write the Spin functions as C++, it shouldn't take long. Most of the time when there is a Spin interface to an assembly driver, it is very simplistic.
    3) Also check out this short thread which goes over all the possible ways to combine C/C++ and Spin: http://forums.parallax.com/discussion/157563/combining-spin-and-c

    So to answer #1, sort of. For C, absolutely. C and C++ both get compiled by the same executable actually - so it's quite easy to combine those two (g++ includes the libstdc++ which is too big for RAM, so PropWare uses gcc for all C and C++ files). Spin is more difficult. I'd give PropWare's current Spin support a 3/10 if I had to rate it. But again, spin2cpp comes to the rescue. Converting from C++ to Spin is harder though - C++ supports many more features as a language than Spin does (that's part of why people like Spin, it is very simple).

    And don't forget the very important aspect of your IDE :D. PropWare and the rarely mentioned OmniaCreator are your only options for utilizing a powerful IDE - SimpleIDE, PropellerIDE, and PropTool are all wonderfully simple, but very lacking in terms of features that professional developers are used to with the likes of Eclipse and JetBrains products.

    And finally #4: no. The Propeller 1 does not have interrupts and PropWare does not include any magic to add them :)
  • Thanks David. I am an avid Eclipse user (Mars 1 on Ubuntu 14.04 is my current environment).
    It looks like a weekend of C, Spin and C++ coming up.

    Thanks to all of you for your responses.
  • DavidZemon wrote: »
    And spin has less overhead for calling methods, so tight loops that invoke a function are much slower in C or C++.

    Really? Why? I thought Spin function calls were expensive compared to PASM ones! Does the CMM kernel not have bytecodes (or whatever) for calls and returns or something? If not, why doesn't someone fix that?

    I really don't think that's true at all. I went back to the original thread and converted the Spin code to C++, and as expected the C++ version was about twice as fast at text drawing as the Spin one (both used the same PASM helper). Obviously if you compare different algorithms or implementations the results will vary, but if you take the same code doing the same thing I don't think you'll ever see C be slower than Spin (as long as you remember to optimize the C code... if you compile without optimization then the Spin may end up faster).
  • ersmith wrote: »
    DavidZemon wrote: »
    And spin has less overhead for calling methods, so tight loops that invoke a function are much slower in C or C++.

    Really? Why? I thought Spin function calls were expensive compared to PASM ones! Does the CMM kernel not have bytecodes (or whatever) for calls and returns or something? If not, why doesn't someone fix that?

    I really don't think that's true at all. I went back to the original thread and converted the Spin code to C++, and as expected the C++ version was about twice as fast at text drawing as the Spin one (both used the same PASM helper). Obviously if you compare different algorithms or implementations the results will vary, but if you take the same code doing the same thing I don't think you'll ever see C be slower than Spin (as long as you remember to optimize the C code... if you compile without optimization then the Spin may end up faster).

    That's really interesting. Can you post your code so I can compare it with the version I tested?
  • Yes, I think LMM C will always be faster than Spin. The Spin VM is very slow. It is effectively a 0.5 MIPS machine. Every operation in Spin goes through the stack. There is no concept of registers in Spin. Just setting a variable to zero requires loading the value 0 on the stack, and then popping the 0 off the stack and storing it in memory. That 3 hub accesses. For a register variable in C this can be done in a single PASM instruction with no hub accesses.
  • Sorry, when doing benchmarks with Spin, I think it is only fair to compare CMM. Like you said, compiled LMM will always be faster than Spin so there is little point. CMM, however, is a much more interesting comparison.
  • DavidZemon wrote: »
    Cool! Can you provide binary sizes for each of this as well?

    How about assembly listings? We can get a nice assembly listing of the C version of fibo by doing:
      propeller-elf-gcc -Os -mcmm -S -o fibo.s fibo.c
      propeller-elf-as -al --cmm fibo.s
    
    GAS LISTING fibo.s 			page 1
    
    
       1              		.text
       2              		.global	_fibo
       3              	_fibo
       4 0000 034C     		lpushm	#(4<<4)+12
       5 0002 BD       		mov	r13, #0
       6 0003 0BC0E0   		xmov	r12,r0 mov r14,r0
       7              	.L3
       8 0006 2E13     		cmp	r14, #1 wz,wc
       9 0008 7E0C     		IF_BE	 brs	#.L2
      10 000a E00E11   		xmov	r0,r14 sub r0,#1
      11 000d 2E21     		sub	r14, #2
      12 000f 060000   		lcall	#_fibo
      13 0012 1D00     		add	r13, r0
      14 0014 7FF0     		brs	#.L3
      15              	.L2
      16 0016 E00C14   		xmov	r0,r12 and r0,#1
      17 0019 10D0     		add	r0, r13
      18 001b 054F0000 		lpopret	#(4<<4)+15
      18      00
    
    The "xmov" operator is a CMM macro that combines a mov with a following instruction to pack 2 instructions in 3 bytes.

    openspin doesn't have a listing option, but bstc does: it produces the following for the Spin version of fibo:
    PUB fibo(x)
    
    Local Parameter DBASE:0000 - Result
    Local Parameter DBASE:0004 - x
    |===========================================================================|
    Addr : 0020:             64  : Variable Operation Local Offset - 1 Read
    Addr : 0021:          37 00  : Constant Mask Y=0 00000002
    Addr : 0023:             F9  : Math Op <     
    Addr : 0024: JZ Label0002
    Addr : 0024:          0A 02  : jz Address = 0028 2
    Addr : 0026:             64  : Variable Operation Local Offset - 1 Read
    Addr : 0027:             33  : Return value  
    Addr : 0028: Label0002
    Addr : 0028: Label0003
    Addr : 0028:             00  : Drop Anchor Push 
    Addr : 0029:             64  : Variable Operation Local Offset - 1 Read
    Addr : 002A:             36  : Constant 2 $00000001
    Addr : 002B:             ED  : Math Op -     
    Addr : 002C:          05 01  : Call Sub 1    
    Addr : 002E:             00  : Drop Anchor Push 
    Addr : 002F:             64  : Variable Operation Local Offset - 1 Read
    Addr : 0030:          37 00  : Constant Mask Y=0 00000002
    Addr : 0032:             ED  : Math Op -     
    Addr : 0033:          05 01  : Call Sub 1    
    Addr : 0035:             EC  : Math Op +     
    Addr : 0036:             33  : Return value  
    Addr : 0037: Data : 32                       2
    

    So the CMM version of fibo is 32 bytes long (including 3 bytes of padding at the end) and the Spin version is 24 bytes long.
  • gis667en11 wrote: »
    PASM: It's the only way to run a program FROM a Cog. It's significantly, absurdly faster than any other option. High speed communication? Shift in/ out, bit banging high speed signals, PASM is the only option.
    Actually no. Both PropBasic and PropGCC can produce code that runs in a Cog. I've written a C version of "pong" that fits both the game and a VGA driver in a single COG. Driving video is pretty bit banging intensive, but it needed no PASM at all.

    I do agree that PASM is a very easy assembly language to use, though -- Chip did a great job in designing the instruction set for assembly programmers.
  • gis667en11gis667en11 Posts: 73
    edited 2016-01-06 - 14:46:23
    Wait, wait, I'm a little confused. Do C programs compile to Spin, PASM, or a combination?
  • gis667en11 wrote: »
    Wait, wait, I'm a little confused. Do C programs compile to Spin, PASM, or a combination?

    There are 3 ways to use C:

    (1) "COG" mode: the C code is compiled to raw binary that runs directly on the COG (just like PASM does).
    (2) "LMM" mode: the C code is compiled to PASM like instructions that are read from hub. This requires a very simple interpreter to fetch the instructions and execute them, but the overhead is low.
    (3) "CMM" mode: the C code is compiled to bytecode which is interpreted. This is the same way Spin works, but the bytecode is different.
  • gis667en11 wrote: »
    Wait, wait, I'm a little confused. Do C programs compile to Spin, PASM, or a combination?

    PropGCC compiles differently depending on the memory model selected. COG, LMM and all XMM memory models produce standard PASM instructions, with LMM and XMM models also containing a PASM kernel.

    CMM memory model produces "spin like" 8-bit instructions that are interpreted by a "spin like" kernel. The result is that CMM is reasonably similar to Spin in both binary size and execution speed.
  • Dave Hein wrote: »

    @Mickster, I believe PropBASIC supports COG and LMM modes. I don't think it has a CMM mode.

    Ah, my mistake. I was assuming CMM was Cog Memory Model.

    Thanks for correcting me.

    Cheers.
  • DavidZemon wrote: »
    ersmith wrote: »
    DavidZemon wrote: »
    And spin has less overhead for calling methods, so tight loops that invoke a function are much slower in C or C++.

    Really? Why? I thought Spin function calls were expensive compared to PASM ones! Does the CMM kernel not have bytecodes (or whatever) for calls and returns or something? If not, why doesn't someone fix that?

    I really don't think that's true at all. I went back to the original thread and converted the Spin code to C++, and as expected the C++ version was about twice as fast at text drawing as the Spin one (both used the same PASM helper). Obviously if you compare different algorithms or implementations the results will vary, but if you take the same code doing the same thing I don't think you'll ever see C be slower than Spin (as long as you remember to optimize the C code... if you compile without optimization then the Spin may end up faster).

    That's really interesting. Can you post your code so I can compare it with the version I tested?

    It's in the http://forums.parallax.com/discussion/157357/radio-shack-lcd-c-vs-spin-vs-pasm-grudge-match thread, but here it is again (I'm not sure how to link to individual posts). Also, note that I was comparing CMM to Spin; obviously the LMM version is tremendously faster.
  • DavidZemon wrote: »
    Sorry, when doing benchmarks with Spin, I think it is only fair to compare CMM. Like you said, compiled LMM will always be faster than Spin so there is little point. CMM, however, is a much more interesting comparison.

    I'm not aware of any case where the CMM is slower than Spin either (provided that we're comparing apples to apples, i.e. the exact same algorithms). There was a claim in the TFT thread that Spin was faster than CMM, but it was apples to oranges -- Spin + PASM is faster than CMM without PASM, but that shouldn't be a big surprise.
  • ersmith wrote: »
    DavidZemon wrote: »
    Sorry, when doing benchmarks with Spin, I think it is only fair to compare CMM. Like you said, compiled LMM will always be faster than Spin so there is little point. CMM, however, is a much more interesting comparison.

    I'm not aware of any case where the CMM is slower than Spin either (provided that we're comparing apples to apples, i.e. the exact same algorithms). There was a claim in the TFT thread that Spin was faster than CMM, but it was apples to oranges -- Spin + PASM is faster than CMM without PASM, but that shouldn't be a big surprise.

    I think that claim was me. And I thought it was apples-to-apples (it was supposed to be, and if it wasn't then I made a mistake), so I'm very curious to get home tonight and try this again, comparing the original spin, your C++, and my C++.
  • potatoheadpotatohead Posts: 10,117
    edited 2016-01-06 - 16:48:45
    @cybersack here is what you know now: You can pick one and go. Lots of good people here who know more than enough to make it work.

    This little chip will do a lot more than it often gets credit for.

    @David Betz, yes SPIN varies from about .3MIPS to a little over .5 depending. A long time ago, I benchmarked it on a couple of tasks against 8 bit computer assembly. It's very comparable. (1 to ~2mhz 6502)
  • DavidZemon wrote: »
    ersmith wrote: »
    I'm not aware of any case where the CMM is slower than Spin either (provided that we're comparing apples to apples, i.e. the exact same algorithms). There was a claim in the TFT thread that Spin was faster than CMM, but it was apples to oranges -- Spin + PASM is faster than CMM without PASM, but that shouldn't be a big surprise.

    I think that claim was me. And I thought it was apples-to-apples (it was supposed to be, and if it wasn't then I made a mistake), so I'm very curious to get home tonight and try this again, comparing the original spin, your C++, and my C++.
    I'm curious too, so please let us know what you find! It's certainly possible that there's a bug in spin2cpp which caused it to output some incorrect code. I don't actually have a TFT screen to check the output. OTOH the results are about what I've seen from other code: generally CMM is about twice the speed of Spin, and 20%-50% larger.
  • DavidZemonDavidZemon Posts: 2,905
    edited 2016-01-06 - 17:31:32
    ersmith wrote: »
    DavidZemon wrote: »
    ersmith wrote: »
    I'm not aware of any case where the CMM is slower than Spin either (provided that we're comparing apples to apples, i.e. the exact same algorithms). There was a claim in the TFT thread that Spin was faster than CMM, but it was apples to oranges -- Spin + PASM is faster than CMM without PASM, but that shouldn't be a big surprise.

    I think that claim was me. And I thought it was apples-to-apples (it was supposed to be, and if it wasn't then I made a mistake), so I'm very curious to get home tonight and try this again, comparing the original spin, your C++, and my C++.
    I'm curious too, so please let us know what you find! It's certainly possible that there's a bug in spin2cpp which caused it to output some incorrect code. I don't actually have a TFT screen to check the output. OTOH the results are about what I've seen from other code: generally CMM is about twice the speed of Spin, and 20%-50% larger.

    Oh, I just remembered a detail. The comparison I was making where I found C++ to be slower was when there was no assembly. I think there was a Spin driver that was written entirely in Spin with no PASM driver. So I copied that into C++ and it wasn't as fast with CMM.
  • DavidZemon wrote: »
    Oh, I just remembered a detail. The comparison I was making where I found C++ to be slower was when there was no assembly. I think there was a Spin driver that was written entirely in Spin with no PASM driver. So I copied that into C++ and it wasn't as fast with CMM.

    I just tried the same exercise with the original SS_TFT.spin (the one without PASM):
    Spin compiled with openspin SS_TFT.spin:
    
    size: 3756 bytes
    Initialization time: 20095 ms
    Text print time: 1591 ms
    
    CMM compiled with spin2cpp --binary -Os -mcmm SS_TFT.spin:
    
    size: 7168 bytes
    Initialization time: 13774 ms
    Text print time: 1148 ms
    
    That is with gcc 6 rather than gcc 4, but I wouldn't expect a huge difference between the compilers. CMM is still faster, although the edge is smaller than I would have expected.

    I think the original Arduino C code may be slower than this... I don't know, I don't have it to compare. OTOH some things may have changed in the translation to .spin, so again, apples to apples...
  • Thanks for sharing!
Sign In or Register to comment.