Assembly Code Examples for the Beginner — Parallax Forums

# Assembly Code Examples for the Beginner

Posts: 892
edited 2014-01-12 20:21
Morning all,

I've just started into Propeller Assembly and I am having some issues with controlling/reading pins.

I can set a pin high using

But how do I set it LOW?· I would assume from SX assembler you'd need a AND of all the pin bits bar pin10 in this case - i.e %111111111111111011111111111 (etc)· Is there an easier way to do this?

```or      dira, SPI_ASM_CLK   ' output
or      outa, SPI_ASM_CLK   ' HIGH
....
SPI_ASM_CLK             long |< 10

```

I assume the same applies to DIRA and setting input(0) and output(1) modes

Then reading pins - I am using the following code - to read INA state:

```                                                mov     input,  #0                         '  Zero input
or      input,  INA                        '  Place the state of all the pins into input
and     input,  SPI_ASM_DI                 '  Place the state of SDA into input

test    input,  SPI_ASM_DI       WC        '  If input AND SDA = 0 &#61627; WZ=1 else = 1 &#61627; WZ=0
if_c    shl     spiASMData,#1
if_c    or      spiASMData,#1
if_nc   shl     spiASMData,#1
.....

SPI_ASM_DI  long |< 11
```

I get values back from it, but wrong ones.

As always grateful for any help!

James

Moderator Edit: By popular request this thread is being made a sticky.

Post Edited By Moderator (Chris Savage (Parallax)) : 8/21/2006 5:19:48 PM GMT

• Posts: 501
edited 2006-08-20 11:37
xor outa, SPI_ASM_CLK 'Toggle SPI_ASM_CLK

You were off by one letter!

Read the definition of XOR. Basically, only when both xor'd variable are 0's or 1's, you get a zero. When they are opposite, xor 0 with 1, you get a 1. See page 271 in the manual, then write out (like in 3rd grade arithmatic) the 32 bit "outa" and xor it with 32 bit "SPI_ASM_CLK".

If OUTA was on/high/1
OUTA
0000_0101_0011_0111_0000_0110_0110_0001
SPI_ASM_CLK--0000_0000_0000_0000_0000_0010_0000_0000
Result-OUTA----0000_0101_0011_0111_0000_0100_0110_0001

If OUTA was off/low/0
OUTA
0000_0101_0011_0111_0000_0100_0110_0001
SPI_ASM_CLK--0000_0000_0000_0000_0000_0010_0000_0000
Result-OUTA----0000_0101_0011_0111_0000_0110_0110_0001

In assy, it is simply the easiest way to toggle a pin state.

-Parsko

Post Edited (parsko) : 8/20/2006 11:42:23 AM GMT
• Posts: 892
edited 2006-08-20 12:32
Parsko,

Doesn't that mean that i would need to know the state of the pin before I try to set it high or low?

Im not looking to toggle, but to set the pin state.

Thanks,

James
• Posts: 23,101
edited 2006-08-20 13:08
Use the ANDN instruction with a bit mask to set the pin low (or direction to input) and the OR instruction with the same bit mask to set the pin high (or direction to output). You can use the XOR instruction (with the same bit mask) to toggle the state of the pin.
• Posts: 892
edited 2006-08-20 13:28
Mike,

Thanks thats what I was after!

James
• Posts: 501
edited 2006-08-20 15:40
James,

Sorry, I thought you just wanted to toggle it. When you set a pin to output, doesn't mean it is high, only that it is an output. Mike, I think they should add something that explicit in the manual, you said it well.

-Luke
• Posts: 892
edited 2006-08-20 15:49
Agreed, I did look but could'nt see anything in the manual for this. The ANDN was too well hidden!

A few more ASM examples in the manual would be helpful!

Thanks for your help!

James
• Posts: 6,487
edited 2006-08-21 04:11
My personal opinion on this matter is to use a data MASK for the PIN you want to affect via the Propeller MUX commands.

```Example #1 (Set Pin as a OUTPUT - Preset with LOW)

mov     t1,             #1        wz      '     Configure Pin
shl     t1,             Pin               '          Create Mask with t1
muxz    outa,           t1                '          PreSet DataPin LOW           "0"
muxnz   dira,           t1                '          Set DataPin to an OUTPUT     "1"

Example #2 (Set Pin as a OUTPUT - Preset with HIGH)

mov     t1,             #1        wz      '     Configure Pin
shl     t1,             Pin               '          Create Mask with t1
muxnz   outa,           t1                '          PreSet DataPin HIGH          "1"
muxnz   dira,           t1                '          Set DataPin to an OUTPUT     "1"

Example #3 (Set Pin as a INPUT )

mov     t1,             #1        wz      '     Configure Pin
shl     t1,             Pin               '          Create Mask with t1
muxz    dira,           t1                '          Set DataPin to an INPUT      "0"

```

'Pin' holds a value ranging between 0 and 31 corresponding to the I/O pin you want to affect.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 8/21/2006 4:19:52 AM GMT
• Posts: 501
edited 2006-08-21 07:25
Beau,

I feel that it is about time that there was an Assembly Tutorial Sticky containing examples just like this, in the same manner that there is a Spin beginners guide. A logical orgainization of it would be nice, but to have one place to look for assy examples would be more nice. I know I could post a few after my "high speed Shiftin" experiences...

-Parsko
• Posts: 6,487
edited 2006-08-21 17:01
I agree with the "Assembly Tutorial Sticky" .... The next post is to expand on the earlier examlpes I gave and to start an Assembly Sticky

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.
• Posts: 6,487
edited 2006-08-21 17:01
Using a data MASK for I/O control via the Propeller MUX commands:

```{
Example #1 (Set Pin as a OUTPUT - Preset with LOW)
}
[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

[b]mov[/b]     t1,             #1        [b]wz[/b]      '     Configure Pin
[b]shl[/b]     t1,             Pin               '          Create Mask with t1
[b]muxz[/b]    [b]outa[/b],           t1                '          PreSet Pin LOW           "0"
[b]muxnz[/b]   [b]dira[/b],           t1                '          Set Pin to an OUTPUT     "1"

Pin           [b]long[/b]      1                               'I/O Pin
t1            [b]res[/b]       1                               'Pin Mask

{
Example #2 (Set Pin as a OUTPUT - Preset with HIGH)
}
[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

[b]mov[/b]     t1,             #1        [b]wz[/b]      '     Configure Pin
[b]shl[/b]     t1,             Pin               '          Create Mask with t1
[b]muxnz[/b]   [b]outa[/b],           t1                '          PreSet Pin HIGH          "1"
[b]muxnz[/b]   [b]dira[/b],           t1                '          Set Pin to an OUTPUT     "1"

Pin           [b]long[/b]      1                               'I/O Pin
t1            [b]res[/b]       1                               'Pin Mask

{
Example #3 (Set Pin as a INPUT )
}
[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

[b]mov[/b]     t1,             #1        [b]wz[/b]      '     Configure Pin
[b]shl[/b]     t1,             Pin               '          Create Mask with t1
[b]muxz[/b]    [b]dira[/b],           t1                '          Set Pin to an INPUT      "0"

Pin           [b]long[/b]      1                               'I/O Pin
t1            [b]res[/b]       1                               'Pin Mask

{
'Pin' holds a value ranging between 0 and 31 corresponding to the I/O pin you want to affect.

What I have been doing recently is to preserve the "mask" associated to each pin that I am using...
in this [b]case[/b] 't1'.  By preserving the "mask" you can use other commands to conviently read or write
to a specific bit.
}

{
Example #4 (Set P0 as an INPUT [b]and[/b] Set P16 an OUTPUT ; Show status of P0 on P16)
}
[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

Initialize
[b]mov[/b]       t1,           #1        [b]wz[/b]      '     Configure Output pin
[b]shl[/b]       t1,           #16               '          Create mask with t1      - #P16 LED
[b]muxz[/b]      [b]outa[/b],         t1                '          Preset Output Pin LOW    "0"
[b]muxnz[/b]     [b]dira[/b],         t1                '          Set pin as Output        "1"

[b]mov[/b]       t2,           #1        [b]wz[/b]      '     Configure Input pin
[b]shl[/b]       t2,           #0                '          Create mask with t2      - #P0 I/O
[b]muxz[/b]      [b]dira[/b],         t2                '          Set pin as Input         "0"
Loop
[b]test[/b]      t2,           [b]ina[/b]        [b]wc[/b]     '     Read Input pin via 't2' mask
[b]muxc[/b]      [b]outa[/b],         t1                '     Write Output pin via 't1' mask
[b]jmp[/b]       #Loop

t1            [b]res[/b]       1                               'Output Mask
t2            [b]res[/b]       1                               'Input Mask

{
Example #5 (Simple ShiftIn routine)
}
[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

Initialize
[b]mov[/b]       t1,           #1        [b]wz[/b]      '     Configure Output pin
[b]shl[/b]       t1,           #1                '          Create mask with t1      - #P1 Clock
[b]muxz[/b]      [b]outa[/b],         t1                '          Preset Output Pin LOW    "0"
[b]muxnz[/b]     [b]dira[/b],         t1                '          Set pin as Output        "1"

[b]mov[/b]       t2,           #1        [b]wz[/b]      '     Configure Input pin
[b]shl[/b]       t2,           #0                '          Create mask with t2      - #P0 Data
[b]muxz[/b]      [b]dira[/b],         t2                '          Set pin as Input         "0"

[b]mov[/b]       t3,           #8                '     Set number of bits to 8

Loop          [b]mov[/b]       t1,           #0      [b]wz[/b],[b]nr[/b]     '     Clock Pin
[b]muxz[/b]      [b]outa[/b],         t1                '          Set ClockPin HIGH
[b]muxnz[/b]     [b]outa[/b],         t1                '          Set ClockPin LOW

'     Shift Bits in
[b]test[/b]      t2,           [b]ina[/b]     [b]wc[/b]        '          Read Data Bit into 'C' flag
[b]rcl[/b]       t4,           #1                '          rotate "C" flag into return value

[b]djnz[/b]      t3,           #Loop             '      Decrement t3 ; jump if not Zero

t1            [b]res[/b]       1                               'Clock Mask
t2            [b]res[/b]       1                               'Data Mask
t3            [b]res[/b]       1                               'Number of Bits
t4            [b]res[/b]       1                               'Received Data

```

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 8/21/2006 7:21:59 PM GMT
• Posts: 892
edited 2006-08-21 17:06
Beau,

Thanks for the post! Very useful!

James
• Posts: 501
edited 2006-08-21 18:50
Beau,

Please include the minimum SPIN code. Your example is not so obvious to the beginners that other stuff is necessary. I've got an easy one that might be more ahead of what you suggested to start. It will toggle a pin endlessly...

```con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
pub Toggle_Main
cognew (@Toggle, 0)
dat
org       0
Toggle
mov     dira,   Pin                'Set Pin to output
mov     Time,   cnt                'Place the value of cnt into Time
add     Time,   #9                 'Add 9 to time
:loop
waitcnt Time,   Delay              'Set Pin high
xor     outa,   Pin                'Toggle Pin
waitcnt Time,   Delay              'Set Pin Low
xor     outa,   Pin                'Toggle Pin
jmp     #:loop

Pin     long            |< 1
Delay   long            40_000_000
Time                    res 1

```

The waitcnt command KILLED me for what seemed to be weeks before the went off.

Short of what is happening to waitcnt goes like this, if one were to run through the program line for line:

```con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
pub Toggle_Main
cognew (@Toggle, 0)
dat
org       0
Toggle     'This will indicate cnt=0
mov     dira,   Pin              'cnt=0-3   Set Pin to output
mov     Time,   cnt            'cnt=4-7   Place the value of cnt into Time
add     Time,   #9             'cnt=8-11   Add 9 to time
:loop
waitcnt Time,   Delay       'cnt=12-15   wait until the system counter (cnt) is equal to Time
'then add the value of Delay to Time or Time=Time+Delay or Time=15+40_000_000
xor     outa,   Pin             'cnt=40_000_016-40_000_019   Toggle Pin
waitcnt Time,   Delay       'cnt=40_000_020-40_000_023   wait until cnt equals Time
xor     outa,   Pin             'cnt=80_000_024-80_000_027 or cnt=24-27 because the counter wraps   Toggle Pin

Pin     long            |< 1
Delay   long            40_000_000
Time                    res 1

```

The important note is that you must set the time value of waitcnt before waiting for it. The system will wait until cnt = Time. If your value for Time is less than the system counter at the time the waitcnt command is executed, the COG will pause until CNT wraps around, or about 53 seconds at 80Mhz. So, it sits there waiting, then adds Delay to Time. This is the value that will be used in the NEXT waitcnt command (aka the value used at cnt=40_000_020 above).

Gotta go set the table, more to come...

-Parsko
• Posts: 6,487
edited 2006-08-21 18:59
Assembly Code Examples for the Beginner: SPI Engine Demo

This Assembly demo illustrates:

1) a Simple SPI Engine (Serial Periphial Interface)
2) Setting up an "Assembly Function" method to be used within Spin
3) A method for passing variables back-n-forth between Spin and Assembly

```[b]CON[/b]
[b]_clkmode[/b] = [b]xtal[/b]1 + [b]pll[/b]16x
[b]_xinfreq[/b] = 5_000_000

#0,MSBPRE,LSBPRE,MSBPOST,LSBPOST                                            'Used for SHIFTIN routines
#4,LSBFIRST,MSBFIRST                                                        'Used for SHIFTOUT routines
#0,Dpin,Cpin,SLpin,#8,Bits                                                  'Set Dpin,Cpin,SLpin and Bit constant

[b]VAR[/b]     [b]long[/b]          DataValue

[b]OBJ[/b]     SPI     : "SPI Engine"

[b]PUB[/b] start
{
Once called [b]from[/b] Spin, SHIFTIN [b]or[/b] SHIFTOUT remains running in its own COG.
[b]If[/b] SHIFTIN [b]or[/b] SHIFTOUT are called with 'Bits' set to Zero, then the COG will shut
down.  Another way to shut the COG down is to [b]call[/b] 'stop' from Spin.
}
'------------------------------------------------------------------------------------------------------------------------------
DataValue := %10001011                                                      'DEBUG - Test value

SPI.SHIFTOUT(Dpin, Cpin, MSBFIRST, Bits, DataValue)                         'Send SHIFTOUT DataVAlue

'DEBUG - Tested with 74HCT164
'        for MSBFIRST and LSBFIRST functions
'------------------------------------------------------------------------------------------------------------------------------
[b]dira[/b][noparse][[/noparse]23..16&#093; := %11111111                                                   'DEBUG - Make ALL LED's outputs

[b]dira[/b][noparse][[/noparse]SLpin&#093; := %1                                                           'Set Shift / Load pin as an output
[b]repeat[/b]
[b]outa[/b][noparse][[/noparse]SLpin&#093; := %1                                                         'Set Shift / Load pin in shift mode "1"
DataValue := SPI.SHIFTIN(Dpin, Cpin, MSBPRE, Bits)                        'Get SHIFTIN DataValue
[b]outa[/b][noparse][[/noparse]SLpin&#093; := %0                                                         'Set Shift / Load pin in load mode "0"

[b]outa[/b][noparse][[/noparse]23..16&#093; := DataValue                                                 'DEBUG - Lightup the LED's corresponding to the data
'        LED23 = MSB
'        LED16 = LSB
'------------------------------------------------------------------------------------------------------------------------------
{{

Notes:
Consecutive SHIFTIN/SHIFTOUT updates through Spin at 80 MHz is about 14kHz (Bit rate about 112k)

Consecutive SHIFTIN/SHIFTOUT updates through Assembly at 80 MHz is about 310kHz (Bit rate about 2.5M)

}}

```

```{
********************************************
SPI Engine             V1.1
********************************************
coded by Beau Schwabe (Parallax)
********************************************
Revision History:
V1.0   - original program

V1.1   - fixed problem with SHIFTOUT MSBFIRST option
- fixed argument allocation in the SPI Engines main loop
}
[b]CON[/b]
#1,_SHIFTOUT,_SHIFTIN
[b]VAR[/b]
[b]long[/b]     cog, command, Flag
[b]PUB[/b] SHIFTOUT(Dpin, Cpin, Mode, Bits, Value)             'Once called from Spin, SHIFTOUT remains running in its own COG.
[b]if[/b] Flag == 0                                        'If SHIFTOUT is called with 'Bits' set to Zero, then the COG will shut
start                                            'down.  Another way to shut the COG down is to call 'stop' from Spin.
setcommand(_SHIFTOUT, @Dpin)
[b]PUB[/b] SHIFTIN(Dpin, Cpin, Mode, Bits)|Value               'Once called from Spin, SHIFTIN remains running in its own COG.
[b]if[/b] Flag == 0                                        'If SHIFTIN is called with 'Bits' set to Zero, then the COG will shut
start                                            'down.  Another way to shut the COG down is to call 'stop' from Spin.
setcommand(_SHIFTIN, @Dpin)
[b]result[/b] := Value
'------------------------------------------------------------------------------------------------------------------------------
[b]PUB[/b] start : okay
'' Start SPI Engine - starts a cog
'' returns false if no cog available
stop
Flag := 1
okay := cog := [b]cognew[/b](@loop, @command) + 1
[b]PUB[/b] stop
'' Stop SPI Engine - frees a cog
Flag := 0
[b]if[/b] cog
[b]cogstop[/b](cog~ - 1)
command~
[b]PRI[/b] setcommand(cmd, argptr)
command := cmd << 16 + argptr                       'write command and pointer
[b]repeat[/b] [b]while[/b] command                                'wait for command to be cleared, signifying receipt
'################################################################################################################
[b]DAT[/b]           [b]org[/b]
'
' SPI Engine - main loop
'
loop          [b]rdlong[/b]  t1,[b]par[/b]          [b]wz[/b]                'wait for command
[b]if_z[/b]  [b]jmp[/b]     #loop
[b]movd[/b]    :arg,#arg0                        'get 5 arguments ; arg0 to arg4
[b]mov[/b]     t2,t1                             '    &#9474;
[b]mov[/b]     t3,#5                             '&#61626;&#9472;&#9472;&#9472;&#9496;
:arg          [b]rdlong[/b]  arg0,t2
[b]djnz[/b]    t3,#:arg
[b]mov[/b]     address,t1                        'preserve address location for passing
'variables back to Spin language.
[b]wrlong[/b]  zero,[b]par[/b]                          'zero command to signify command received
[b]ror[/b]     t1,#16+2                          'lookup command address
[b]movs[/b]    :table,t1
[b]rol[/b]     t1,#2
[b]shl[/b]     t1,#3
:table        [b]mov[/b]     t2,0
[b]shr[/b]     t2,t1
[b]and[/b]     t2,#\$FF
jumps         [b]byte[/b]    0                                 '0
[b]byte[/b]    SHIFTOUT_                         '1
[b]byte[/b]    SHIFTIN_                          '2
[b]byte[/b]    NotUsed_                          '3
NotUsed_      [b]jmp[/b]     #loop
'################################################################################################################
SHIFTOUT_                                               'SHIFTOUT Entry
[b]mov[/b]     t4,             arg3      [b]wz[/b]      '     Load number of data bits
[b]if_z[/b]      [b]jmp[/b]     #Done                             '     '0' number of Bits = Done
[b]mov[/b]     t1,             #1        [b]wz[/b]      '     Configure DataPin
[b]shl[/b]     t1,             arg0
[b]muxz[/b]    [b]outa[/b],           t1                '          PreSet DataPin LOW
[b]muxnz[/b]   [b]dira[/b],           t1                '          Set DataPin to an OUTPUT
[b]mov[/b]     t2,             #1        [b]wz[/b]      '     Configure ClockPin
[b]shl[/b]     t2,             arg1
[b]muxz[/b]    [b]outa[/b],           t2                '          PreSet ClockPin LOW
[b]muxnz[/b]   [b]dira[/b],           t2                '          Set ClockPin to an OUTPUT
[b]sub[/b]     LSBFIRST,       arg2    [b]wz[/b],[b]nr[/b]     '     Detect LSBFIRST mode for SHIFTOUT
[b]if_z[/b]      [b]jmp[/b]     #LSBFIRST_
[b]sub[/b]     MSBFIRST,       arg2    [b]wz[/b],[b]nr[/b]     '     Detect MSBFIRST mode for SHIFTOUT
[b]if_z[/b]      [b]jmp[/b]     #MSBFIRST_
[b]jmp[/b]     #loop                             '     Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
SHIFTIN_                                                'SHIFTIN Entry
[b]mov[/b]     t4,             arg3      [b]wz[/b]      '     Load number of data bits
[b]if_z[/b]      [b]jmp[/b]     #Done                             '     '0' number of Bits = Done
[b]mov[/b]     t1,             #1        [b]wz[/b]      '     Configure DataPin
[b]shl[/b]     t1,             arg0
[b]muxz[/b]    [b]dira[/b],           t1                '          Set DataPin to an INPUT
[b]mov[/b]     t2,             #1        [b]wz[/b]      '     Configure ClockPin
[b]shl[/b]     t2,             arg1
[b]muxz[/b]    [b]outa[/b],           t2                '          PreSet ClockPin LOW
[b]muxnz[/b]   [b]dira[/b],           t2                '          Set ClockPin to an OUTPUT
[b]sub[/b]     MSBPRE,         arg2    [b]wz[/b],[b]nr[/b]     '     Detect MSBPRE mode for SHIFTIN
[b]if_z[/b]      [b]jmp[/b]     #MSBPRE_
[b]sub[/b]     LSBPRE,         arg2    [b]wz[/b],[b]nr[/b]     '     Detect LSBPRE mode for SHIFTIN
[b]if_z[/b]      [b]jmp[/b]     #LSBPRE_
[b]sub[/b]     MSBPOST,        arg2    [b]wz[/b],[b]nr[/b]     '     Detect MSBPOST mode for SHIFTIN
[b]if_z[/b]      [b]jmp[/b]     #MSBPOST_
[b]sub[/b]     LSBPOST,        arg2    [b]wz[/b],[b]nr[/b]     '     Detect LSBPOST mode for SHIFTIN
[b]if_z[/b]      [b]jmp[/b]     #LSBPOST_
[b]jmp[/b]     #loop                             '     Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
MSBPRE_                                                 '     Receive Data MSBPRE
MSBPRE_Sin    [b]test[/b]    t1,             [b]ina[/b]     [b]wc[/b]        '          Read Data Bit into 'C' flag
[b]rcl[/b]     t3,             #1                '          rotate "C" flag into return value
[b]call[/b]    #Clock                            '          Send clock pulse
[b]djnz[/b]    t4,             #MSBPRE_Sin       '          Decrement t4 ; jump if not Zero
[b]jmp[/b]     #Update_SHIFTIN                   '     Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBPRE_                                                 '     Receive Data LSBPRE
LSBPRE_Sin    [b]test[/b]    t1,             [b]ina[/b]       [b]wc[/b]      '          Read Data Bit into 'C' flag
[b]rcr[/b]     t3,             #1                '          rotate "C" flag into return value
[b]call[/b]    #Clock                            '          Send clock pulse
[b]djnz[/b]    t4,             #LSBPRE_Sin       '     Decrement t4 ; jump if not Zero
[b]mov[/b]     t4,             #32               '     For LSB shift data right 32 - #Bits when done
[b]sub[/b]     t4,             arg3
[b]shr[/b]     t3,             t4
[b]jmp[/b]     #Update_SHIFTIN                   '     Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
MSBPOST_                                                '     Receive Data MSBPOST
MSBPOST_Sin   [b]call[/b]    #Clock                            '          Send clock pulse
[b]test[/b]    t1,             [b]ina[/b]     [b]wc[/b]        '          Read Data Bit into 'C' flag
[b]rcl[/b]     t3,             #1                '          rotate "C" flag into return value
[b]djnz[/b]    t4,             #MSBPOST_Sin      '          Decrement t4 ; jump if not Zero
[b]jmp[/b]     #Update_SHIFTIN                   '     Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBPOST_                                                '     Receive Data LSBPOST
LSBPOST_Sin   [b]call[/b]    #Clock                            '          Send clock pulse
[b]test[/b]    t1,             [b]ina[/b]       [b]wc[/b]      '          Read Data Bit into 'C' flag
[b]rcr[/b]     t3,             #1                '          rotate "C" flag into return value
[b]djnz[/b]    t4,             #LSBPOST_Sin      '          Decrement t4 ; jump if not Zero
[b]mov[/b]     t4,             #32               '     For LSB shift data right 32 - #Bits when done
[b]sub[/b]     t4,             arg3
[b]shr[/b]     t3,             t4
[b]jmp[/b]     #Update_SHIFTIN                   '     Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBFIRST_                                               '     Send Data LSBFIRST
[b]mov[/b]     t3,             arg4              '          Load t3 with DataValue
LSB_Sout      [b]test[/b]    t3,             #1      [b]wc[/b]       '          Test LSB of DataValue
[b]muxc[/b]    [b]outa[/b],           t1                '          Set DataBit HIGH or LOW
[b]shr[/b]     t3,             #1                '          Prepare for next DataBit
[b]call[/b]    #Clock                            '          Send clock pulse
[b]djnz[/b]    t4,             #LSB_Sout         '          Decrement t4 ; jump if not Zero
[b]mov[/b]     t3,             #0      [b]wz[/b]        '          Force DataBit LOW
[b]muxnz[/b]   [b]outa[/b],           t1
[b]jmp[/b]     #loop                             '     Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
MSBFIRST_                                               '     Send Data MSBFIRST
[b]mov[/b]     t3,             arg4              '          Load t3 with DataValue
[b]mov[/b]     t5,             #%1               '          Create MSB mask     ;     load t5 with "1"
[b]shl[/b]     t5,             arg3              '          Shift "1" N number of bits to the left.
[b]shr[/b]     t5,             #1                '          Shifting the number of bits left actually puts
'          us one more place to the left than we want. To
'          compensate we'll shift one position right.
MSB_Sout      [b]test[/b]    t3,             t5      [b]wc[/b]        '          Test MSB of DataValue
[b]muxc[/b]    [b]outa[/b],           t1                '          Set DataBit HIGH or LOW
[b]shr[/b]     t5,             #1                '          Prepare for next DataBit
[b]call[/b]    #Clock                            '          Send clock pulse
[b]djnz[/b]    t4,             #MSB_Sout         '          Decrement t4 ; jump if not Zero
[b]mov[/b]     t3,             #0      [b]wz[/b]        '          Force DataBit LOW
[b]muxnz[/b]   [b]outa[/b],           t1

[b]jmp[/b]     #loop                             '     Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
Update_SHIFTIN
[b]mov[/b]     t1,             address           '     Write data back to Arg4
[b]add[/b]     t1,             #16               '          Arg0 = #0 ; Arg1 = #4 ; Arg2 = #8 ; Arg3 = #12 ; Arg4 = #16
[b]wrlong[/b]  t3,             t1
[b]jmp[/b]     #loop                             '     Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
Clock
[b]mov[/b]     t2,             #0      [b]wz[/b],[b]nr[/b]     '     Clock Pin
[b]muxz[/b]    [b]outa[/b],           t2                '          Set ClockPin HIGH
[b]muxnz[/b]   [b]outa[/b],           t2                '          Set ClockPin LOW
Clock_ret     [b]ret[/b]                                       '          return
'------------------------------------------------------------------------------------------------------------------------------
Done                                                    '     Shut COG down
[b]mov[/b]     t2,             #0                '          Preset temp variable to Zero
[b]mov[/b]     t1,             [b]par[/b]               '          Read the address of the first perimeter
[b]add[/b]     t1,             #4                '          Add offset for the second perimeter ; The 'Flag' variable
[b]wrlong[/b]  t2,             t1                '          Reset the 'Flag' variable to Zero
[b]CogID[/b]   t1                                '          Read CogID
[b]COGSTOP[/b] t1                                '          Stop this Cog!
'------------------------------------------------------------------------------------------------------------------------------
{
########################### Defined data ###########################
}
zero                    [b]long[/b]    0                       'constants
d0                      [b]long[/b]    \$200

MSBPRE                  [b]long[/b]    \$0                      '          Applies to SHIFTIN
LSBPRE                  [b]long[/b]    \$1                      '          Applies to SHIFTIN
MSBPOST                 [b]long[/b]    \$2                      '          Applies to SHIFTIN
LSBPOST                 [b]long[/b]    \$3                      '          Applies to SHIFTIN
LSBFIRST                [b]long[/b]    \$4                      '          Applies to SHIFTOUT
MSBFIRST                [b]long[/b]    \$5                      '          Applies to SHIFTOUT
{
########################### Undefined data ###########################
}
'temp variables
t1                      [b]res[/b]     1                       '     Used for DataPin mask     and     COG shutdown
t2                      [b]res[/b]     1                       '     Used for CLockPin mask    and     COG shutdown
t3                      [b]res[/b]     1                       '     Used to hold DataValue SHIFTIN/SHIFTOUT
t4                      [b]res[/b]     1                       '     Used to hold # of Bits
t5                      [b]res[/b]     1                       '     Used for temporary data mask
address                 [b]res[/b]     1                       '     Used to hold return address of first Argument passed

arg0                    [b]res[/b]     1                       'arguments passed to/from high-level Spin
arg1                    [b]res[/b]     1
arg2                    [b]res[/b]     1
arg3                    [b]res[/b]     1
arg4                    [b]res[/b]     1

```

Edit: updated SPI engine....
fixed problem with SHIFTOUT MSBFIRST option
fixed argument allocation in the SPI Engines main loop

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 8/24/2006 4:40:19 AM GMT

• Posts: 23,294
edited 2006-08-21 20:07
Beau (and others),

I think we need to get this copyright thing straightened out. A lot of Propeller code origniating from Parallax (like the SPI Engine above) includes a copyright notice, but no licensing terms. The rules for the Propeller Object Exchange state "no copyrights", which implies public domain (and which is the reason I've never posted anything there). I think a copyright is important, along with a reasonable license for sharing the code. I prefer the General Public License (GPL) for this, and any significant code that I've originated and posted in various forum threads contains those terms of use.

The reasons for having a copyright are several:

1. It allows one to control the attributions that appear in the code, yielding a provenance than can be traced back to the originator.

2. It prevents someone else from copyiing the code and claiming it as their own, as could happen with code in the public domain.

3. It allows one to set restrictions on how the code may be used and distributed, keeping it "free", for example, as the GPL does.

But if copyrighted code is meant to be shared, it needs to say so, even though that intent in the context of the forum might seem clear. Once a program is copied from the forum context, any implied consent disappears. My vote would be to standardize on the GPL for shared Propeller code and to remove the "no copyrights" restriction from the object exchange in favor of that license.

I don't mean to stir up a hornet's nest here, but there are presently some inconsistencies and ambiguities that leave me a little uneasy.

Thanks,
Phil
• Posts: 6,487
edited 2006-08-21 20:21
Phil,

You bring up a good point. I will find out what the proper "Header" should look like in released code from Parallax.
What I have been using for the Header of objects that I have been posting originates from objects such as 'Keyboard.spin', 'Mouse.spin', etc....

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.
• Posts: 6,487
edited 2006-08-22 19:42
It took me a little while to figure this out, so I thought I would pass this along as an Assembler "trap"

Notice, Marker #1 that starts a cognew at TestMode2...

Running this test I would expect LED #16 and LED #17 to turn on.
The actual result is that none of the LED's turn on.

You could change Marker #1 so that it starts a cognew at TestMode1,
and then both LED's would turn on. However for illustration purposes,
TestMode1 happens to do something similar to TestMode2, but it could
be anything.

Remarking the 'call' statement on Marker #4 will cause LED #17 to turn
on as expected and LED #16 will remain off ... as expected. SO why, since
the section between Marker 5&6 is the same as the section between 7&8, won't
this program run the way that it is without remarking the 'call' on Marker #4?

The answer is the way that 'cognew' needs to load your assembly program.
The proper way is to load or start the cog at the top most assembly code
position. In this case the line at Marker #1 should read...

```cognew(@TestMode1,0)

```

...Now at TestMode1 if you want to run or start at TestMode2 then you need a
'jmp' at TestMode1 that points to TestMode2

One more thing to watch out for that has to do with the 'call' function mentioned
in the book is the way that the 'ret' gets encoded into the returning address.
If the lines between Markers 8&9 looked like this...

```#8
ret
InitializePins_ret
#9

```

... Then when 'InitializePins' was actually called, this procedure would not know
where to return. Instead 'ret' MUST be on the same line as the '{Routine}_ret'
in order to properly execute.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 8/22/2006 7:51:54 PM GMT
• Posts: 23,294
edited 2006-08-22 21:47
Beau,

You can also pile up return labels in a subroutine with multiple entry points (or even for multiple subroutines, for that matter, if memory is really tight):

```Sub_entry1
...Entry1 stuff...
[b]jmp[/b] #Common

Sub_entry2
...Entry2 stuff...

Common
...Common stuff...

Sub_entry1_ret
Sub_entry2_ret [b]ret[/b]

```

Also, if you need to branch to a subroutine's return point, you don't need to do an immediate jmp. An indirect jmp not only works fine, but saves four clocks:

```Sub
...
[b]jmp[/b]  Sub_ret
...
Sub_ret    [b]ret[/b]

```

The reason this works is that the return address is stored in the src field of the "return" instruction. The indirect jump just picks it up and uses it, instead of going to Sub_ret first.

-Phil
• Posts: 23,101
edited 2006-08-22 22:52
```'' Here's a simple example of table lookup in assembly.
'' This particular example takes a table index in "ptr"
'' and sets the "data" to the word value from the table.
'' There's no range checking.  If you want long values,
'' just eliminate the shifts and masks (*).  You can use
'' the same kind of logic for byte values.

DAT
org   0
test      mov   ptr,#2        ' for an example, get third value
call  #look            ' note table indices are 0 to n-1
:stop     jmp   #:stop        ' no checking for out of range

look         mov    data,ptr      ' ptr is a table index (0 to n-1)
shr   data,#1       ' divide input value by 2 to get (*)
movs   :inline,data   ' have to use instruction modification
nop                        ' need pause here for pipelining
:inline    mov    data,0-0         ' get long value from table
test   ptr,#1   wz     ' do we want odd or even half  (*)
if_z     and    data,mask       ' if even, take lower 16 bits (*)
if_nz   shr    data,#16         ' if odd, take upper 16 bits  (*)
look_ret   ret
table       word    \$0000
word    \$C0C1
word    \$C181
word    \$0140
word    \$C301
word    \$03C0
word    \$0280
data        res     1
ptr          res     1

```

Post Edited (Mike Green) : 8/23/2006 3:37:17 PM GMT
• Posts: 6,487
edited 2006-08-30 15:35
I had mentioned earlier that I preferred using the Propeller MUX operator to affect an I/O pin.
I am still with this belief, however it is application dependent. There are certainly other
times that it is better to use 'or' or 'andn' to affect an I/O bit. The savings can be a few
clock cycles and an extra programming 'long' ...for large applications this can make a big
difference. On smaller applications sometimes you just want to get the job done and it doesn't
really matter one way or the other.

Typically to affect an I/O pin on a 32-bit register you need to create what's known as a 'mask'
To set up a mask simply initialize a mask variable to "1" and then shift that variable left by
the number of bits you wish. For an I/O this translates to the pin you want to access.

Example1:

```              [b]mov[/b]     PinMask,            #1                '     Set Bit

```

To define an I/O pin as an input we can use the 'andn' operator AFTER we have created a 'mask'.

Example2:

```              [b]andn[/b]    [b]dira[/b],            PinMask                '     Make Pin an Input

```

By using the 'or' operator instead, we can define the I/O pin as an output.

Example3:

```              [b]or[/b]      [b]dira[/b],            PinMask                '     Make Pin an Output

```

Using the same 'or' operator and directing it toward 'outa' instead of 'dira' we can define the
pin state as HIGH if we also make the I/O pin an output.

Example4:

```              [b]or[/b]      [b]outa[/b],            PinMask                '     Make Pin HIGH

```

Likewise if we use the 'andn' operator we can define the pin state as being LOW if we also make
the I/O pin an output.

Example5:

```              [b]andn[/b]    [b]outa[/b],            PinMask                '     Make Pin LOW

```

Suppose we want to affect an I/O pin based on a variable or another I/O pin. One way to do it
using the 'andn' and 'or' operators is to test the variable or pin with a 'mask' and write to
the 'z' flag using the 'if_z' and 'if_nz' conditionals.

Example6:

```              [b]mov[/b]     InPinMask,        #1                '     Set Bit
[b]andn[/b]    [b]dira[/b],                     InPinMask                       '     Make Pin an input

[b]mov[/b]     OutPinMask,        #1                '     Set Bit
[b]or[/b]      [b]dira[/b],                     OutPinMask                      '     Make Pin an output

[b]test[/b]    InPinMask,                [b]ina[/b]          [b]wz[/b]                 '     Test InpinMask against the I/O port
[b]if_z[/b]  [b]andn[/b]    [b]outa[/b],                     OutPinMask                      '          If InPin = 0 set OutPin - LOW
[b]if_nz[/b] [b]or[/b]      [b]outa[/b],                     OutPinMask                      '          If InPin = 1 set OutPin - HIGH

```

Another way to accomplish the same task is to use the 'mux' operator.

Example7:

```              [b]mov[/b]     InPinMask,        #1                '     Set Bit
[b]andn[/b]    [b]dira[/b],                     InPinMask                       '     Make Pin an input

[b]mov[/b]     OutPinMask,        #1                '     Set Bit
[b]or[/b]      [b]dira[/b],                     OutPinMask                      '     Make Pin an output

[b]test[/b]    InPinMask,                [b]ina[/b]          [b]wz[/b]                 '     Test InpinMask against the I/O port
[b]muxnz[/b]   [b]outa[/b],                     OutPinMask                      '          If InPin = 0 set OutPin - LOW
'          If InPin = 1 set OutPin - HIGH

```

Now, this may not seem like a huge amount of savings, but this type of scenario has a way of
multiplying itself as a program gets larger, and it can make a difference in the long run with
some applications. Example 8 is a complete Propeller assembly program of Example 7.

Example8: I/O follower

```[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

[b]mov[/b]     InPinMask,                #1                              '     Set Bit
[b]andn[/b]    [b]dira[/b],                     InPinMask                       '     Make Pin an input

[b]mov[/b]     OutPinMask,               #1                              '     Set Bit
[b]or[/b]      [b]dira[/b],                     OutPinMask                      '     Make Pin an output

loop          [b]test[/b]    InPinMask,                [b]ina[/b]     [b]wz[/b]                      '     Test Data bit at BitMask position
[b]muxnz[/b]   [b]outa[/b],                     OutPinMask                      '          If InPin = 0 set OutPin - LOW
'          If InPin = 1 set OutPin - HIGH
[b]jmp[/b]       #loop

InPin         [b]long[/b]      0                            'I/O pin 0
OutPin        [b]long[/b]      16                            'I/o PIN 16 (DEMO Board LED)

```

Example9: MSB - SHIFTIN

```[b]PUB[/b] start
[b]cognew[/b](@entry, 0)

[b]DAT[/b]

entry         [b]org[/b]

Initialize
[b]mov[/b]       ClockPinMask,           #1        [b]wz[/b]                    '     Configure Output pin
[b]shl[/b]       ClockPinMask,           ClockPin                        '          Create mask with ClockPin
[b]andn[/b]      [b]outa[/b],                   ClockPinMask                    '          Preset Output Pin LOW    "0"
[b]or[/b]        [b]dira[/b],                   ClockPinMask                    '          Set pin as Output        "1"

[b]mov[/b]       DataPinMask,            #1        [b]wz[/b]                    '     Configure Input pin
[b]shl[/b]       DataPinMask,            DataPin                         '          Create mask with DataPin
[b]andn[/b]      [b]dira[/b],                   DataPinMask                     '          Set pin as Input         "0"

SHIFTIN       [b]mov[/b]       DataBitMask,            #1                              '     Create BitMask
[b]shl[/b]       DataBitMask,            DataBits                        '     Set number of Bits
[b]mov[/b]       Data,                   #0                              '     Clear Data
_ReadNextBit  [b]or[/b]        [b]outa[/b],                   ClockPinMask                    '     Set Clock pin HIGH  - Start Clock
[b]test[/b]      DataPinMask,            [b]ina[/b]     [b]wc[/b]                      '     Load "C" with DataPin value
[b]muxc[/b]      Data,                   DataBitMask                     '     Move "C" into Data via DataBitMask position
[b]andn[/b]      [b]outa[/b],                   ClockPinMask                    '     Set Clock pin LOW   - End Clock
[b]shr[/b]       DataBitMask,            #1      [b]wz[/b]                      '     Move BitMask position right by 1           '

ClockPin      [b]long[/b]      0                                                       '     Define I/O Clock Pin
DataPin       [b]long[/b]      1                                                       '     Define I/O Data Pin
DataBits      [b]long[/b]      7                                                       '     Set number of Data Bits ( N = Bits - 1 = [noparse][[/noparse]0 to 31] )

Data          [b]res[/b]       1                                                       '     Holds result value from SHIFTIN

```

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.
• Posts: 32
edited 2006-11-08 03:25
How would I write an assembler routine that would add two numbers and return the result back to the spin object?
• Posts: 6,487
edited 2006-11-08 04:38
UPDATE TO THIS POST!!!····· 04 - 21 - 2007

please see the following thread for an update to this post

LucidGuppy,

This example will launch a cog just to run the Assembly, then add the two numbers and stop the cog after returning the result.

```[b]PUB[/b] AddNums(Num1,Num2)
Num1_ := Num1
Num2_ := Num2
[b]cognew[/b](@entry, @Num1)

[b]DAT[/b]
[b]org[/b]
entry                   [b]add[/b]     Num1_,Num2_     'Add Num1 to Num2
[b]wrlong[/b]  Num1_, [b]par[/b]      'Return result to Num1
[b]CogId[/b]   CogNum          'Get COG ID
[b]CogStop[/b] CogNum          'Stop this COG

CogNum                  [b]long[/b]    0               'Reserved variables
Num1_                   [b]long[/b]    0
Num2_                   [b]long[/b]    0

```

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 4/21/2007 5:07:01 PM GMT
• Posts: 32
edited 2006-11-08 12:32
Thanks Beau,

I'll give this a try tonight. Seems like a lot of people are way ahead of me and I need to catch up.
• Posts: 0
edited 2006-12-04 17:38
Beau ,

·Where do the results go ? and how can you "look" at them ?

Thanks , Brian
• Posts: 8,122
edited 2006-12-04 17:57
Beau,
How long does it take to start/stop a new cog with an assembly program ?
If I have a routine that isn't fast enough in spin, I know it would be faster in assembly, but I don't know what the time delay is to launch a new cog.

Bean.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheap used 4-digit LED display with driver IC·www.hc4led.com

Low power SD Data Logger www.sddatalogger.com
SX-Video Display Modules www.sxvm.com
Stuff I'm selling on ebay http://search.ebay.com/_W0QQsassZhittconsultingQQhtZ-1

"People who are willing to trade their freedom for·security deserve neither and will lose both." Benjamin Franklin
·
• Posts: 23,101
edited 2006-12-04 17:58
Brian,
The results (_Num1) are computed in a memory location within the cog's memory space (512 32-bit words). The main memory which
is used by the SPIN interpreter is separate. To the program running in the cog, the main memory looks a bit like an I/O device with
special instructions needed to access it. In particular, the "wrlong <cog address>,<hub address>" instruction writes the contents of
the specified cog location into a main (hub) memory location whose address is in a cog location (in this case, the PAR register). The PAR
register is a read-only cog memory location that contains a hub memory long-word address specified when the cog was started (by the
COGINIT/COGNEW instruction).

You can only "look" at the results of an assembly program by the assembly program itself copying the results into the common hub memory
for other programs (whether in SPIN or assembly) to examine. You could also send the results to an I/O device by manipulating the I/O pins.
Mike
• Posts: 6,487
edited 2006-12-05 07:02
truckwiz,

If you treat 'AddNums(Num1,Num2)' as a function, then when you call it with something like...

Your result will be returned in the variable 'Answer'

To 'look' at them, use any of the other objects available to display them to a TV,VGA,SERIAL,LED's(binary form) etc.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.
• Posts: 6,487
edited 2006-12-05 07:59
Bean,

I've been in Rocklin and Tahoe all of this weekend, and while I was in the Parallax office on Friday and Monday, I was busy going over layout ideas with Chip
and did not have a chance to do any timing tests with the Propeller that would answer your question.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.
• Posts: 8,122
edited 2006-12-05 14:03
Beau,
I didn't actually measure the time, but it's pretty fast (much faster than the same code in spin).

I was thinking it had to load the cog from EEPROM, but now that I think about it, I guess it just loads from hub memory into cog memory (which is much faster than pulling the data from the EEPROM).

Bean.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheap used 4-digit LED display with driver IC·www.hc4led.com

Low power SD Data Logger www.sddatalogger.com
SX-Video Display Modules www.sxvm.com
Stuff I'm selling on ebay http://search.ebay.com/_W0QQsassZhittconsultingQQhtZ-1

"People who are willing to trade their freedom for·security deserve neither and will lose both." Benjamin Franklin
·
• Posts: 501
edited 2006-12-10 01:23
This is kind of a trap, I suppose. The following pertinent inputs:
```[b]VAR[/b]
[b]byte[/b] array[noparse][[/noparse]100]
[b]PUB[/b]
[b]cognew[/b](@assembly, @second)
[b]DAT[/b]
Assembly
.
.
.

```

This code is legal. But any new cognew's that occur, must have a PARameter registered to some value of the array/4. Let me say that another way, it's late. I used "@second[noparse][[/noparse]4]" for my PARameter. I could have easily used "@second[noparse][[/noparse]0]" or "@second[noparse][[/noparse]8]". The cognew requeires the start of a long for it's parameter. So, if you want to use "@second[noparse][[/noparse]2]" it will still start at second[noparse][[/noparse]0]. Subsequently, @second[noparse][[/noparse]6] will start at @second[noparse][[/noparse]4] {The less obvious concept I'm pointing out}

-Parsko

Post Edited (parsko) : 12/10/2006 1:27:55 AM GMT
• Posts: 23,101
edited 2006-12-10 02:29
Because of the way the COGINIT/COGNEW assembly instruction works, there is only a 14 bit field available for initializing the PAR register. Because this value is most likely to be used as the address of a long, it appears in the PAR register shifted left by 2 bits (a multiple of 4). SPIN makes the same assumption and throws away the low order 2 bits of the address supplied. The Propeller Manual says this several times, but it is a trap for the unwary.