Shop OBEX P1 Docs P2 Docs Learn Events
Pepper SPIN with Assembly? — Parallax Forums

Pepper SPIN with Assembly?

HumanoidoHumanoido Posts: 5,770
edited 2010-09-14 08:02 in Propeller 1
I'm writing some arbitrary SPIN code and I see lots of small
snippets of assembly code that I would like to use, like this.
MOV $1F4, #$FF   'Set OUTA 7:0 high

To what degree can these small snippets of assembly
code, without any other support, be mixed with SPIN?

Thank you in advance.

Humanoido

Comments

  • Heater.Heater. Posts: 21,230
    edited 2010-09-12 09:39
    Not at all.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-09-12 09:44
    There's no provision for mixing Spin and assembly except by loading a whole block of assembly code into its own cog and executing it. Since the loading process (COGINIT / COGNEW) takes about 100us regardless of how much code you want to load, it's not very practical for small code blocks.
  • Heater.Heater. Posts: 21,230
    edited 2010-09-12 09:56
    Sorry , that was a bit curt.

    Problem is that to run any PASM instructions you have to get them loaded into a COGs memory space first.

    The Cog that is executing your Spin code is already full, with the Spin byte code interpreter. Even if it were not full it's unlikely any one would design the interpreter to suck in any old instructions and run them [See note 1].

    So you would have to load that PASM into a different COG. But you can only load a whole COG (496) LONGs so it would be a slow process just for a couple of instructions.

    Even if you do that you are then left with the problem of communicating with that PASM snippet through HUB memory. It's just not worth it.

    So result is "Not at all."

    Note 1: I'm considering allowing the Zog byte code interpreter for C to allow loading and executing of any PASM instruction as it runs. Not intended for use by application programs but as a way for C code to be able to do waitxxx and hubops like COGINIT etc.
  • tonyp12tonyp12 Posts: 1,951
    edited 2010-09-12 12:05
    Should it not be possible make a patched
    version of the spin interpreter that allows this?
    Store this version on the upper half of a 64kb eeprom, and load a cog with it
    and end the current rom based interprete cog.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-09-12 12:12
    Yes, there has been some work on a modified Spin interpreter that allows for small snippets of assembly. This was done by moving some infrequently used byte codes out of the cog so they're executed this way allowing other snippets to be used as well.
  • TimmooreTimmoore Posts: 1,031
    edited 2010-09-12 12:14
    Look at spinlmm in obex, it patches part of the spin interpreter to allow inline pasm. Note the pasm doesn't run at full speed, instructions need to be loaded from hub into cog memory and then executed.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-09-12 20:15
    There might be a roundabout solution using propbasic and the c compilers - there is a Spin compiler thread running at the moment and Quarkspin is looking at writing a python code to convert spin to basic (or C). Then compile that code. Because those compilers use LMM and compile rather than interpret code, it could be a way to mixing spin and single lines of pasm. And other things, like a Spin program that is 200k long and has pasm mixed through the code.

    I'd find this sort of thing useful, for both writing programs, and also for learning pasm, as you could take a single pasm instruction and put it in amongst some high level code that might read a keyboard, or print something to a screen, and then you can experiment with pasm and debug code fragments more easily.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2010-09-13 20:58
    Not to step on any toes of what you can or can't do, or what is technically considered In-Line Assembly ...

    ... but for small code snippets, this has been working really nice for me. It might help others as well.

    http://obex.parallax.com/objects/665/

    or in the code below...
    {{      
    ************************************************
    * InLine PAsm in Spin Demo                v1.0 *
    * Author: Beau Schwabe                         *
    * Copyright (c) 2010 Parallax                  *
    * See end of file for terms of use.            *
    ************************************************
    
    
    InLine Assembly? - debatable perhaps, however this allows you to call snippets of PAsm and run them
    as if they are a defined PUB or PRI subroutine without having to reload a new COG every time.  This
    program starts a single COG engine which is similar to 'other' dispatch type of PAsm programs such as
    'graphics.spin'.  What makes this different is that the PAsm that would normally be dispatched within
    the PAsm dispatcher program now resides in Spin and because of that can be more dynamic (customized)
    from within the Spin environment even making some LMM programming possible.
    
    
    Revision History:
    
    (sometime before)               - I have been using a form very similar to this for testing small bits of code
                                      for awhile.  There has been some recent talk in the forums so I decided to clean
                                      up what I hav and sumbit it.
                                       
    09-13-2010                      - initial release
    
    }}
    
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    VAR
    long InlinePAsm,ARG0{...,ARG1,ARG2,ARG3, etc.}
    
    PUB SpinCode
        cognew(@PAsmEntry,@InlinePAsm)  'Start Inline PAsm engine - You only need to launch this once
    
    
    
    ''Example 1
        Inline(@PAsm1)              'Call Inline PAsm:
                                     ' - set all LED's on Propeller Demo Board HIGH
                                     ' - program returns to Spin after LEDs have been set in PAsm
    
    ''Example 2
    '    Inline(@PAsm2)              'Call Inline PAsm ;
                                     ' - how to make jumps .. wiggles P0 at 5MHz
                                     ' - program remains in PAsm loop does not return back to Spin
    
    ''Example 3
    '    ARG0 := %11001010
    '    Inline(@PAsm3)              'Call Inline PAsm ;
                                     ' - how to pass an argument from Spin to PAsm
                                     ' - program returns to Spin after LEDs have been set in PAsm    
    
    ''Example 4
    '    Inline(@PAsm4)              'Call Inline PAsm ;
                                     ' - how to pass an argument from PAsm to Spin
                                     ' - program returns to Spin after PAsm changes ARG0                                 
    
    '    dira[23..16]~~
    '    outa[23..16]:=ARG0
    
        repeat    
                
    DAT
    {{
    
              Enter valid Assembly code here in this section, there are just a few stipulations/requirements
              you need to consider about how variables are used, and how jumping is achieved.  Because
              addresses and variables are local to each COG and how the IDE computes adresses it is necessary,
              when running 'PAsm code snips' to make relative jumps from a known position.
    
    }}
    ''################################################################################################
    ''################################################################################################
    ''################################################################################################
    ''################################################################################################
    
    
    
    
    ''      InLine PAssembly code example 1
    ''################################################################################################
    PAsm1         long      PAsm1_End-PAsm1        '<-first value must contain InLine PAsm program
                                                   '  length in longs
                  
                            mov     temp0,          #%11111111
                            shl     temp0,          #16
                            mov     dira,           temp0
                            mov     outa,           temp0
    
    PAsm1_End                                      '<- place this at the end of each InLine PAsm
                                                   '   for a convenient way to calculate program
                                                   '   length  
    
    ''      InLine PAssembly code example 2                                  
    ''################################################################################################
    PAsm2         long      PAsm2_End-PAsm2        '<-first value must contain InLine PAsm program
                                                   '  length in longs
    
            {0}             mov     temp0,          #1
            {1}             mov     dira,           temp0
    
            {2}             xor     outa,           temp0
            {3}             jmp     #InlineProg+2
    
    ''       &#61600;                             &#61600;        Note: In order to jmp to any location within the InLine
    ''       &#9474;                             &#9474;              PAsm code, you must do it with reference to where
    ''       &#9474;                             &#9474;              your Inline code starts.  This means that YOU must
    ''       &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#61610;  keep track of the PC location and add it to
    ''                                     &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#61610;  'InlineProg' to get an effective jump
                            
    PAsm2_End                                      '<- place this at the end of each InLine PAsm
                                                   '   for a convenient way to calculate program
                                                   '   length  
    
    ''      InLine PAssembly code example 3                                  
    ''################################################################################################
    PAsm3         long      PAsm3_End-PAsm3        '<-first value must contain InLine PAsm program
                                                   '  length in longs
    
                            mov     temp0,          #%11111111  'make first 8 bits of temp0 HIGH                         
                            shl     temp0,          #16         'shift temp0 left by 16
                            mov     dira,           temp0       'use temp0 as a mask to set the
                                                                'direction of the LEDs on the Propeller
                                                                'Demo Board
    
                            mov     temp0,          par         'First par address contains the size
                                                                'of the InLine PAssmebly program...
                                                                
                            add     temp0,          #4          '...we don't want that so we move to
                                                                'the next long to get the address for ARG0
                                                                
                            rdlong  temp1,          temp0       'This reads the contents of ARG0 into temp1,
                                                                'effectively passing ARG0 into PAsm 
    
                            shl     temp1,          #16         'This block of code alligns the data we                             
                            mov     outa,           temp1       'passed into PAsm to the position of the
                                                                'LEDs on the Propeller Demo Board so we can
                                                                'see the bit pattern 
                            
    PAsm3_End                                      '<- place this at the end of each InLine PAsm
                                                   '   for a convenient way to calculate program
                                                   '   length  
    
    ''      InLine PAssembly code example 4                                  
    ''################################################################################################
    PAsm4         long      PAsm4_End-PAsm4        '<-first value must contain InLine PAsm program
                                                   '  length in longs
    
                            mov     temp1,           #%11100111 '<- Some value we want to pass back to Spin
    
                            mov     temp0,          par         'First par address contains the size
                                                                'of the InLine PAssmebly program...
                                                                
                            add     temp0,          #4          '...we don't want that so we move to
                                                                'the next long to get the address for ARG0
                                                                
                            wrlong  temp1,          temp0       'This reads the contents of ARG0 into temp1,
                                                                'effectively passing ARG0 into PAsm 
                                                                
    PAsm4_End                                      '<- place this at the end of each InLine PAsm
                                                   '   for a convenient way to calculate program
                                                   '   length                                                             
    
    
    
    PRI Inline(StartAddress)                       ''Call Inline PAssembly function
        InlinePAsm := StartAddress                 ' run InLine PAsm code          
        repeat until InlinePAsm == 0               ' wait until code is finished
    
    DAT
    
    ''             InLine Assembly Engine starts here
    ''################################################################################################
    ''################################################################################################
                            org     0
    PAsmEntry               
    loop                    rdlong  SpinPAsmAddress,        par    wz        'wait for InLine PAsm
            if_z            jmp     #loop
    
                            movd    PAsmPointer,            #InlineProg      'Restore/Set the self
                                                                             'modifying pointers 'Destination'
                                                                             'field to the beginning address
                                                                             'of 'InlineProg'                         
    
    ''             Load InLine Assembly from Spin
    '################################################################################################
                            rdlong  ProgramSize,            SpinPAsmAddress  'determine size of InLine
                                                                             'PAsm code in longs +1. Note:
                                                                             'This value is one more than
                                                                             'it should be (remember Zero
                                                                             'counts) in order to append
                                                                             'the 'jmp  #Done' footer code
                                                                             'at the end of the InLine Pasm
                                                                             'code.    
    
                            add     SpinPAsmAddress,        #4               'Increment pointer to
                                                                             'start of InLine PAsm code
                                                                                      
                            rdlong  PAsmDatafromSpin,       SpinPAsmAddress  'get first long of PAsm code
                                                                             'from Spin
    
    PAsmPointer             mov     0-0 {<-the destination address gets self modified}, PAsmDatafromSpin
    '                                &#61600;                                       'Self Modify 'InlineProg' at
    '                                &#9474;                                       'an offset determined by the
    '                        &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;                                       '  'Destination' pointer in
    '                        &#9474;                                               '  'PAsmPointer'
    '                        &#9474;                                                      
                            add     PAsmPointer,            DestMask         'increment the 'Destination'
                                                                             'pointer in 'PAsmPointer' to
                                                                             'the next PC position.
    
                            add     SpinPAsmAddress,        #4               'increment the InLine PAsm
                                                                             'code pointer to the next
                                                                             'instruction
                                                                              
                            rdlong  PAsmDatafromSpin,       SpinPAsmAddress  'get next long of PAsm code
                                                                             'from Spin
    
                            djnz    ProgramSize,            #PasmPointer     'decrement the Program Size
                                                                             'counter and jump if there
                                                                             'is still InLine code to be
                                                                             'coppied
    
    ''             This section places a 'jmp  #Done' at the end of the InLine PAsm code
    '################################################################################################
    
                            mov     FooterCode,             PAsmPointer      'make Copy of 'PAsmPointer'
                                                                             'at 'FooterCode' (Self modify
                                                                             'the nop instruction
                                                                                                              
                            mov     PAsmDatafromSpin,       Footer           'replace the previously read
                                                                             'InLine PAsm instruction from
                                                                             'Spin with the instruction
                                                                             'located at 'Footer' which is
                                                                             'the 'jmp #Done'       
    FooterCode              nop     '<- This line gets self modified to append 'jmp  #Done' to the end of
                                    'the InLine Pasm code
    
    ''            Area defining the location of where the InLine Assembly will be                                                                          
    '################################################################################################                                                                                  
    InlineProg              long      0[50]  {<- the Inline PAsm program area is reserved to 50 longs,
                                                 but you can change that to whatever the program allows
                                                 or whatever particular need you have}                 
    
    '' Clear Flag and Jump to the beginning of the InLine Assembly Engine where we can wait for more code                                                                         
    '################################################################################################                                                                                  
    Done
                            mov     flag,           #0
                            wrlong  flag,           par
                            
                            jmp     #PAsmEntry
    
    Footer                  jmp     #Done           '<- This line never gets executed here.  It's placed
                                                    'as a reference so that upon compile time the calculated
                                                    'value in this location can be used in the self modifying
                                                    'code section to add a 'jmp     #Done' at the end of the
                                                    'In-Line PAsm code block.                                                                      
    
    ''            Variables used for InLine Assembly engine                                                                          
    '################################################################################################                                                                                  
    
    SpinPAsmAddress         {<- note missing long ; this notation causes 'SpinPAsmAddress' and 'flag' to
                                be aliased to the same variable in memory }
                                
    flag                    long    0                        
    
    ProgramSize             long    0
    PAsmDatafromSpin        long    0
    PAsmDataAddress         long    0
    DestMask                long    %1_000000000
    
    
    
    
    
    
    ''            If your In-Line Assembly uses any variables you need to place them here!!!!
    
    '         The reason has to do with the way the variable locations are calculated upon run time.
    '         you can add as many as the program will allow, and you can use whatever names you wish
    '         as long as they don't conflict with the names used above.             
                                                                              
    '################################################################################################                                                                                  
    temp0                   long    0 '<--- These are to be referenced from within the Spin Inline Asm
    temp1                   long    0 '<--- These are to be referenced from within the Spin Inline Asm
    
    DAT
    
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                    TERMS OF USE: MIT License                                    &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and&#9474;
    &#9474;associated documentation files (the "Software"), to deal in the Software without restriction,    &#9474;
    &#9474;including without limitation the rights to use, copy, modify, merge, publish, distribute,        &#9474; 
    &#9474;sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is    &#9474;
    &#9474;furnished to do so, subject to the following conditions:                                         &#9474;
    &#9474;                                                                                                 &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or         &#9474;
    &#9474;substantial portions of the Software.                                                            &#9474;
    &#9474;                                                                                                 &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT&#9474;
    &#9474;NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND           &#9474;
    &#9474;NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,     &#9474;
    &#9474;DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,   &#9474;
    &#9474;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.          &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
  • HumanoidoHumanoido Posts: 5,770
    edited 2010-09-13 21:12
    Not to step on any toes of what you can or can't do, or what is technically considered In-Line Assembly ...
    ... but for small code snippets, this has been working really nice for me. It might help others as well. http://obex.parallax.com/objects/665/ or in the code... InLine Assembly? - debatable perhaps, however this allows you to call snippets of PAsm and run them as if they are a defined PUB or PRI subroutine without having to reload a new COG every time.
    Beau, thank you! This is absolutely spectacular! I am speechless now..

    Humanoido
  • max72max72 Posts: 1,155
    edited 2010-09-14 02:50
    There also is spinlmm

    http://obex.parallax.com/objects/635/

    And some sample objects

    http://obex.parallax.com/objects/636/

    Massimo
  • Heater.Heater. Posts: 21,230
    edited 2010-09-14 03:35
    Beau,

    I haven't fully absorbed what you have done there but it possible to get rid of the need for manually tracking jump target addresses by using ORG. Like this snippet which creates the correct run time jump address in the Pasm1 routine:
    DAT
    'bla
    'bla
    'bla
    
    InlineProg  long  0[50]  'The Inline PAsm program area is reserved to 50 longs,
    
    'bla
    'bla
    'bla
                org InlineProg        'Use org to adjust jumps for
                                      'correct run time address
    
    PAsm2       long PAsm2_End-PAsm2  'First value must contain InLine PAsm program
                                      'length in longs
    
                mov  temp0, #1
                mov  dira, temp0
    
    :loop       xor  outa, temp0
                jmp  :loop
    
    temp0       long 0
    PAsm2_End                          'Place this at the end of
                                       'each InLine PAsm
    

    Basically what you have here is a PASM overlay loader controlled from Spin, sneaky.
    Anyone who wants to do this should check out the tricks used in Cluso's overlay loader. From which I learned the ORG thing:)
  • Heater.Heater. Posts: 21,230
    edited 2010-09-14 03:39
    Humanoido:
    This is absolutely spectacular! I am speechless now..
    

    Don't be. This is "Propeller Land" where impossible things are done every day.

    Notice some idiot in this thread hastily replied "Not at all." to your question:)
  • HumanoidoHumanoido Posts: 5,770
    edited 2010-09-14 06:24
    Heater wrote: Notice some idiot in this thread hastily replied "Not at all." to your question:)
    Heater, don't worry about it. He is my friend.

    It has indeed become a roller coaster ride of ups and downs, of yes's and no's, possible and impossible, blinded guessing and grand visions spot on, a place where you'll meet pure genius from above and hot-hard-heads from down below, where fame is fleeting and success is lasting, a place to get flamed one day and praise-honored the next.. welcome to the Propeller Forum! :)

    Humanoido
  • HumanoidoHumanoido Posts: 5,770
    edited 2010-09-14 06:37
    max72 wrote: »
    There also is spinlmm

    http://obex.parallax.com/objects/635/

    And some sample objects

    http://obex.parallax.com/objects/636/

    Massimo
    Max, thanks for pointing out these supporting gems, each of which has a particular technique. I checked these in the OBEX and they are entirely workable. Now we're multi-enabled from SPIN and can interject PASM for additional programming gains. I really like the overall idea. We can truly pepper SPIN with PASM. I think we just turned the volume control up and amplified our programming capabilities.

    Humanoido
  • max72max72 Posts: 1,155
    edited 2010-09-14 08:02
    I agree, there are evolutions pumping the Propeller.

    When I read around the forum the opinion that propeller power hasn't been fully unleashed I was sceptical... while in fact anything considered impossible for the propeller becomes possible in an impressively short time.

    There are also a couple of objects around in development that could be described as multitasking, if the word wasn't banned from this forum... :-) It means anyway we will probably have in the near future the possibility to use one single COG in place of the 2-4 COGs required until now for the same tasks...
    Both the dispatcher and the inline assy, while not for starters, will bring a lot of power.

    Massimo
Sign In or Register to comment.