Propeller Manual V1.01bmarked
Propeller Manual V1.01bmarked
Version 1.01
WARRANTY
Parallax Inc. warrants its products against defects in materials and workmanship for a period of 90 days from receipt of product.
If you discover a defect, Parallax Inc. will, at its option, repair or replace the merchandise, or refund the purchase price. Before
returning the product to Parallax, call for a Return Merchandise Authorization (RMA) number. Write the RMA number on the
outside of the box used to return the merchandise to Parallax. Please enclose the following along with the returned merchandise:
your name, telephone number, shipping address, and a description of the problem. Parallax will return your product or its
replacement using the same shipping method used to ship the product to Parallax.
This documentation is copyright © 2006 by Parallax Inc. By downloading or obtaining a printed copy of this documentation or
software you agree that it is to be used exclusively with Parallax products. Any other uses are not permitted and may represent a
violation of Parallax copyrights, legally punishable according to Federal copyright or intellectual property laws. Any duplication
of this documentation for commercial uses is expressly prohibited by Parallax Inc. Duplication for educational use is permitted,
subject to the following Conditions of Duplication: Parallax Inc. grants the user a conditional right to download, duplicate, and
distribute this text without Parallax's permission. This right is based on the following conditions: the text, or any portion thereof,
may not be duplicated for commercial use; it may be duplicated only for educational purposes when used solely in conjunction
with Parallax products, and the user may recover from the student only the cost of duplication.
This text is available in printed format from Parallax Inc. Because we print the text in volume, the consumer price is often less
than typical retail duplication charges.
Parallax, Propeller Spin, and the Parallax and Propeller Hat logos are trademarks of Parallax Inc. BASIC Stamp, Stamps in
Class, Boe-Bot, SumoBot, Toddler, and SX-Key are registered trademarks of Parallax, Inc. If you decide to use any trademarks
of Parallax Inc. on your web page or in printed material, you must state that (trademark) is a (registered) trademark of Parallax
Inc.” upon the first appearance of the trademark name in each printed document or web page. Other brand and product names
herein are trademarks or registered trademarks of their respective holders.
ISBN 1-928982-38-7
DISCLAIMER OF LIABILITY
Parallax Inc. is not responsible for special, incidental, or consequential damages resulting from any breach of warranty, or under
any legal theory, including lost profits, downtime, goodwill, damage to or replacement of equipment or property, or any costs of
recovering, reprogramming, or reproducing any data stored in or used with Parallax products. Parallax Inc. is also not
responsible for any personal damage, including that to life and health, resulting from use of any of our products. You take full
responsibility for your Propeller microcontroller application, no matter how life-threatening it may be.
• Propeller chip – This list is specifically for our customers using Propeller chips and products.
• BASIC Stamp – This list is widely utilized by engineers, hobbyists and students who share their BASIC Stamp
projects and ask questions.
• Stamps in Class® – Created for educators and students, subscribers discuss the use of the Stamps in Class
curriculum in their courses. The list provides an opportunity for both students and educators to ask questions
and get answers.
• Parallax Educators – A private forum exclusively for educators and those who contribute to the development of
Stamps in Class. Parallax created this group to obtain feedback on our curricula and to provide a place for
educators to develop and obtain Teacher’s Guides.
• Robotics – Designed for Parallax robots, this forum is intended to be an open dialogue for robotics enthusiasts.
Topics include assembly, source code, expansion, and manual updates. The Boe-Bot®, Toddler®, SumoBot®,
HexCrawler and QuadCrawler robots are discussed here.
• SX Microcontrollers and SX-Key – Discussion of programming the SX microcontroller with Parallax assembly
language SX – Key® tools and 3rd party BASIC and C compilers.
• Javelin Stamp – Discussion of application and design using the Javelin Stamp, a Parallax module that is
programmed using a subset of Sun Microsystems’ Java® programming language.
ERRATA
While great effort is made to assure the accuracy of our texts, errors may still exist. If you find an error, please let us know by
sending an email to editor@parallax.com. We continually strive to improve all of our educational materials and documentation,
and frequently revise our texts. Occasionally, an errata sheet with a list of known errors and corrections for a given text will be
posted to our web site, www.parallax.com. Please check the individual product page’s free downloads for an errata file.
CREDITS
Authorship: Jeff Martin. Format & Editing, Stephanie Lindsay.
Cover Art: Jen Jacobs; Technical Graphics: Rich Allred; with many thanks to everyone at Parallax Inc.
Table of Contents
PREFACE ............................................................................................................................... 12
CHAPTER 1 : INTRODUCING THE PROPELLER CHIP....................................................... 13
CONCEPT ............................................................................................................................. 13
PACKAGE TYPES ................................................................................................................... 14
PIN DESCRIPTIONS ................................................................................................................ 15
SPECIFICATIONS ................................................................................................................... 16
HARDWARE CONNECTIONS .................................................................................................... 17
BOOT UP PROCEDURE .......................................................................................................... 18
RUN-TIME PROCEDURE ......................................................................................................... 18
SHUTDOWN PROCEDURE ....................................................................................................... 19
BLOCK DIAGRAM ................................................................................................................... 20
SHARED RESOURCES ............................................................................................................ 22
SYSTEM CLOCK .................................................................................................................... 22
COGS (PROCESSORS) ........................................................................................................... 22
HUB ..................................................................................................................................... 24
I/O PINS ............................................................................................................................... 26
SYSTEM COUNTER ................................................................................................................ 27
CLK REGISTER ..................................................................................................................... 28
LOCKS .................................................................................................................................. 30
MAIN MEMORY ...................................................................................................................... 30
MAIN RAM ........................................................................................................................... 31
MAIN ROM ........................................................................................................................... 32
CHARACTER DEFINITIONS ...................................................................................................... 32
LOG AND ANTI-LOG TABLES ................................................................................................... 34
SINE TABLE .......................................................................................................................... 34
BOOT LOADER AND SPIN INTERPRETER .................................................................................. 34
CHAPTER 2 : USING THE PROPELLER TOOL.................................................................... 35
CONCEPT ............................................................................................................................. 35
SCREEN ORGANIZATION ........................................................................................................ 37
MENU ITEMS ......................................................................................................................... 45
File Menu........................................................................................................................ 45
Edit Menu ....................................................................................................................... 46
Run Menu ....................................................................................................................... 47
Help Menu ...................................................................................................................... 48
FIND/REPLACE DIALOG.......................................................................................................... 49
OBJECT VIEW ....................................................................................................................... 52
OBJECT INFO ........................................................................................................................ 55
CHARACTER CHART .............................................................................................................. 58
VIEW MODES, BOOKMARKS AND LINE NUMBERS ..................................................................... 61
View Modes .................................................................................................................... 61
Bookmarks...................................................................................................................... 63
Propeller Manual v1.0 · Page 5
Table of Contents
Line Numbers..................................................................................................................64
EDIT MODES .........................................................................................................................65
Insert and Overwrite Modes............................................................................................65
Align Mode ......................................................................................................................66
BLOCK SELECTION AND SELECTION MOVING ...........................................................................68
INDENTING AND OUTDENTING .................................................................................................69
Single Lines.....................................................................................................................70
Multiple Lines ..................................................................................................................71
BLOCK-GROUP INDICATORS ...................................................................................................74
SHORTCUT KEYS ...................................................................................................................75
Categorical Listings.........................................................................................................75
Listing by Key..................................................................................................................80
CHAPTER 3 : PROPELLER PROGRAMMING TUTORIAL....................................................85
CONCEPT ..............................................................................................................................85
PROPELLER LANGUAGES (SPIN AND PROPELLER ASSEMBLY) ..................................................86
PROPELLER OBJECTS ............................................................................................................86
Quick Review: Intro.........................................................................................................91
EXERCISE 1: OUTPUT.SPIN – OUR FIRST OBJECT ...................................................................92
Downloading to RAM vs. EEPROM................................................................................93
Quick Review: Ex 1.........................................................................................................96
COGS (PROCESSORS) ...........................................................................................................97
EXERCISE 2: OUTPUT.SPIN - CONSTANTS ...............................................................................98
BLOCK DESIGNATORS ............................................................................................................99
EXERCISE 3: OUTPUT.SPIN - COMMENTS ..............................................................................100
Quick Review: Ex 2 & 3 ................................................................................................103
EXERCISE 4: OUTPUT.SPIN – PARAMETERS, CALLS, AND FINITE LOOPS .................................104
EXERCISE 5: OUTPUT.SPIN – PARALLEL PROCESSING ...........................................................106
Quick Review: Ex 4 & 5 ................................................................................................109
EXERCISE 6: OUTPUT.SPIN & BLINKER1.SPIN – USING OUR OBJECT ......................................110
THE OBJECT VIEW ...............................................................................................................112
TOP OBJECT FILE ................................................................................................................113
WHICH OBJECTS WERE COMPILED?.....................................................................................115
Quick Review: Ex 6.......................................................................................................116
OBJECTS VS. COGS .............................................................................................................117
EXERCISE 7: OUTPUT.SPIN – MORE ENHANCEMENTS ............................................................117
Quick Review: Ex 7.......................................................................................................123
EXERCISE 8: BLINKER2.SPIN – MANY OBJECTS, MANY COGS ................................................124
OBJECT INFO WINDOW ........................................................................................................128
OBJECT LIFETIME ................................................................................................................129
Quick Review: Ex 8.......................................................................................................130
EXERCISE 9: CLOCK SETTINGS.............................................................................................131
EXERCISE 10: CLOCK-RELATED TIMING ................................................................................133
Page 6 · Propeller Manual v1.0
Table of Contents
Quick Review: Ex 9 & 10.............................................................................................. 137
EXERCISE 11: LIBRARY OBJECTS ......................................................................................... 138
Work and Library Folders ............................................................................................. 141
EXERCISE 12: WHOLE AND REAL NUMBERS ......................................................................... 143
Pseudo-Real Numbers ................................................................................................. 143
Floating-Point Numbers................................................................................................ 144
Context-Sensitive Compile Information ........................................................................ 147
Quick Review: Ex 11 & 12............................................................................................ 148
CHAPTER 4 : SPIN LANGUAGE REFERENCE .................................................................. 149
STRUCTURE OF PROPELLER OBJECTS ................................................................................. 150
CATEGORICAL LISTING OF PROPELLER SPIN LANGUAGE ....................................................... 152
Block Designators......................................................................................................... 152
Configuration ................................................................................................................ 152
Cog Control .................................................................................................................. 153
Process Control ............................................................................................................ 153
Flow Control ................................................................................................................. 153
Memory......................................................................................................................... 154
Directives...................................................................................................................... 155
Registers ...................................................................................................................... 155
Constants ..................................................................................................................... 156
Variable ........................................................................................................................ 156
Unary Operators ........................................................................................................... 156
Binary Operators .......................................................................................................... 157
Syntax Symbols............................................................................................................ 158
SPIN LANGUAGE ELEMENTS ................................................................................................. 159
Symbol Rules ............................................................................................................... 159
Value Representations ................................................................................................. 159
Syntax Definitions......................................................................................................... 160
ABORT ................................................................................................................................. 161
BYTE................................................................................................................................... 165
BYTEFILL............................................................................................................................ 169
BYTEMOVE............................................................................................................................ 170
CASE................................................................................................................................... 171
CHIPVER ............................................................................................................................. 174
CLKFREQ ............................................................................................................................. 175
_CLKFREQ............................................................................................................................ 177
CLKMODE ............................................................................................................................. 179
_CLKMODE............................................................................................................................ 180
CLKSET ............................................................................................................................... 183
CNT..................................................................................................................................... 184
COGID ................................................................................................................................. 186
COGINIT ............................................................................................................................. 187
Propeller Manual v1.0 · Page 7
Table of Contents
COGNEW................................................................................................................................189
COGSTOP ..............................................................................................................................193
CON .....................................................................................................................................194
CONSTANT ............................................................................................................................200
CONSTANTS (PRE-DEFINED) .................................................................................................202
CTRA, CTRB.........................................................................................................................204
DAT .....................................................................................................................................208
DIRA, DIRB.........................................................................................................................212
FILE ...................................................................................................................................215
FLOAT..................................................................................................................................216
_FREE..................................................................................................................................218
FRQA, FRQB.........................................................................................................................219
IF .......................................................................................................................................220
IFNOT..................................................................................................................................225
INA, INB ............................................................................................................................226
LOCKCLR ..............................................................................................................................228
LOCKNEW ..............................................................................................................................230
LOCKRET ..............................................................................................................................233
LOCKSET ..............................................................................................................................234
LONG ...................................................................................................................................236
LONGFILL ............................................................................................................................240
LONGMOVE ............................................................................................................................241
LOOKDOWN, LOOKDOWNZ.........................................................................................................242
LOOKUP, LOOKUPZ................................................................................................................244
NEXT ...................................................................................................................................246
OBJ .....................................................................................................................................247
OPERATORS ........................................................................................................................249
OUTA, OUTB.........................................................................................................................280
PAR .....................................................................................................................................283
PHSA, PHSB.........................................................................................................................285
PRI .....................................................................................................................................286
PUB .....................................................................................................................................287
QUIT ...................................................................................................................................291
REBOOT................................................................................................................................292
REPEAT................................................................................................................................293
RESULT................................................................................................................................299
RETURN................................................................................................................................301
ROUND..................................................................................................................................303
SPR .....................................................................................................................................305
_STACK................................................................................................................................307
STRCOMP ..............................................................................................................................308
STRING................................................................................................................................310
STRSIZE ..............................................................................................................................311
Page 8 · Propeller Manual v1.0
Table of Contents
SYMBOLS............................................................................................................................ 312
TRUNC ................................................................................................................................. 314
VAR..................................................................................................................................... 315
VCFG................................................................................................................................... 317
VSCL................................................................................................................................... 320
WAITCNT ............................................................................................................................. 322
WAITPEQ ............................................................................................................................. 326
WAITPNE ............................................................................................................................. 328
WAITVID ............................................................................................................................. 329
WORD................................................................................................................................... 331
WORDFILL............................................................................................................................ 335
WORDMOVE............................................................................................................................ 336
_XINFREQ............................................................................................................................ 337
CHAPTER 5 : ASSEMBLY LANGUAGE REFERENCE ....................................................... 339
THE STRUCTURE OF PROPELLER ASSEMBLY ........................................................................ 339
CATEGORICAL LISTING OF PROPELLER ASSEMBLY LANGUAGE............................................... 341
Directives...................................................................................................................... 341
Configuration ................................................................................................................ 341
Cog Control .................................................................................................................. 341
Process Control ............................................................................................................ 341
Conditions..................................................................................................................... 341
Flow Control ................................................................................................................. 343
Effects........................................................................................................................... 343
Main Memory Access ................................................................................................... 343
Common Operations .................................................................................................... 343
Registers ...................................................................................................................... 345
Constants ..................................................................................................................... 346
Unary Operators ........................................................................................................... 346
Binary Operators .......................................................................................................... 347
ASSEMBLY LANGUAGE ELEMENTS ........................................................................................ 348
Syntax Definitions......................................................................................................... 348
Propeller Assembly Instruction Master Table............................................................... 349
ABS..................................................................................................................................... 353
ABSNEG ............................................................................................................................... 354
ADD..................................................................................................................................... 354
ADDABS ............................................................................................................................... 355
ADDS................................................................................................................................... 356
ADDSX ................................................................................................................................. 356
ADDX................................................................................................................................... 357
AND..................................................................................................................................... 358
ANDN................................................................................................................................... 359
CALL................................................................................................................................... 360
Propeller Manual v1.0 · Page 9
Table of Contents
CLKSET................................................................................................................................361
CMP .....................................................................................................................................362
CMPS ...................................................................................................................................362
CMPSUB................................................................................................................................363
CMPSX..................................................................................................................................364
CMPX ...................................................................................................................................364
COGID..................................................................................................................................365
COGINIT ..............................................................................................................................366
COGSTOP ..............................................................................................................................367
CONDITIONS ( IF_X ) ............................................................................................................368
DJNZ ...................................................................................................................................370
EFFECTS .............................................................................................................................371
FIT .....................................................................................................................................372
HUBOP..................................................................................................................................373
JMP .....................................................................................................................................374
JMPRET................................................................................................................................374
LOCKCLR ..............................................................................................................................375
LOCKNEW ..............................................................................................................................376
LOCKRET ..............................................................................................................................376
LOCKSET ..............................................................................................................................377
MAX .....................................................................................................................................378
MAXS ...................................................................................................................................378
MIN .....................................................................................................................................379
MINS ...................................................................................................................................380
MOV .....................................................................................................................................380
MOVD ...................................................................................................................................381
MOVI ...................................................................................................................................382
MOVS ...................................................................................................................................382
MUXC ...................................................................................................................................383
MUXNC..................................................................................................................................384
MUXNZ..................................................................................................................................384
MUXZ ...................................................................................................................................385
NEG .....................................................................................................................................386
NEGC ...................................................................................................................................386
NEGNC..................................................................................................................................387
NEGNZ..................................................................................................................................388
NEGZ ...................................................................................................................................389
NOP .....................................................................................................................................389
OPERATORS ........................................................................................................................390
OR .......................................................................................................................................392
ORG .....................................................................................................................................392
RCL .....................................................................................................................................393
RCR .....................................................................................................................................394
Page 10 · Propeller Manual v1.0
Table of Contents
RDBYTE ............................................................................................................................... 394
RDLONG ............................................................................................................................... 395
RDWORD ............................................................................................................................... 396
REGISTERS ......................................................................................................................... 397
RES..................................................................................................................................... 398
RET..................................................................................................................................... 399
REV..................................................................................................................................... 399
ROL..................................................................................................................................... 400
ROR..................................................................................................................................... 400
SAR..................................................................................................................................... 401
SHL..................................................................................................................................... 402
SHR..................................................................................................................................... 402
SUB..................................................................................................................................... 403
SUBABS ............................................................................................................................... 404
SUBS................................................................................................................................... 404
SUBSX ................................................................................................................................. 405
SUBX................................................................................................................................... 406
SUMC................................................................................................................................... 406
SUMNC ................................................................................................................................. 407
SUMNZ ................................................................................................................................. 408
SUMZ................................................................................................................................... 408
TEST................................................................................................................................... 409
TJNZ................................................................................................................................... 410
TJZ..................................................................................................................................... 410
WAITCNT ............................................................................................................................. 411
WAITPEQ ............................................................................................................................. 412
WAITPNE ............................................................................................................................. 413
WAITVID ............................................................................................................................. 414
WRBYTE ............................................................................................................................... 414
WRLONG ............................................................................................................................... 415
WRWORD ............................................................................................................................... 416
XOR..................................................................................................................................... 417
APPENDIX A: RESERVED WORD LIST.............................................................................. 419
APPENDIX B: ACCESSING MATH FUNCTION TABLES ................................................... 420
INDEX ................................................................................................................................... 425
Preface
Thank you for purchasing a Propeller chip. You will be spinning your own programs in no
time!
Propeller chips are incredibly capable multiprocessor microcontrollers; the much-anticipated
result of over eight years of the intense efforts of Chip Gracey and the entire Parallax
Engineering Team.
This book is intended to be a complete reference guide to Propeller chips and their
programming languages, Spin and Propeller Assembly. Have fun!
Despite our best efforts, there are bound to be questions unanswered by this manual alone.
Check out our Propeller chip discussion forum – (accessible from www.parallax.com via the
Support → Discussion Forums menu) – this is a group especially for Propeller users where
you can post your questions or review discussions that may have already answered yours.
Concept
The Propeller chip is designed to provide high-speed processing for embedded systems while
maintaining low current consumption and a small physical footprint. In addition to being
fast, the Propeller provides flexibility and power through its eight processors, called cogs,
that can perform simultaneous independent or cooperative tasks, all while maintaining a
relatively simple architecture that is easy to learn and utilize.
The resulting design of the Propeller frees application developers from common complexities
of embedded systems programming. For example:
• The memory map is flat. There is no need for paging schemes with blocks of code,
data or variables. This is a big time-saver during application development.
• Asynchronous events are easier to handle than they are with devices that use
interrupts. The Propeller has no need for interrupts; just assign some cogs to
individual, high-bandwidth tasks and keep other cogs free and unencumbered. The
result is a more responsive application that is easier to maintain.
• The Propeller Assembly language features conditional execution and optional result
writing for each individual instruction. This makes critical, multi-decision blocks of
code more consistently timed; event handlers are less prone to jitter and developers
spend less time padding, or squeezing, cycles here and there.
Package Types
The Propeller chip is available in the package types shown here.
P8X32A-Q44 P8X32A-M44
44-pin LQFP 44-pin QFN
Pin Descriptions
Table 1-1: Pin Descriptions
Pin Name Direction Description
General purpose I/O Port A. Can source/sink 30 mA each at 3.3 VDC. Do
not exceed 100 mA source/sink total across any group of I/O pins at once.
Logic threshold is ≈ ½ VDD; 1.65 VDC @ 3.3 VDC.
The pins shown below have a special purpose upon power-up/reset but are
P0 – P31 I/O
general purpose I/O afterwards.
P28 - I2C SCL connection to optional, external EEPROM.
P29 - I2C SDA connection to optional, external EEPROM.
P30 - Serial Tx to host.
P31 - Serial Rx from host.
VDD --- 3.3 volt power (2.7 – 3.3 VDC).
The Propeller (P8X32A) has 32 I/O pins (Port A, pins P0 through P31). Four of these I/O
pins, P28-P31 have a special purpose upon power-up/reset. At power-up/reset, pins P30 and
P31 communicate with a host for programming and P28 and P29 interface to an external 32
KB EEPROM (24LC256).
Specifications
Table 1-2: Specifications
Model P8X32A
External Clock Speed DC to 80 MHz (4 MHz to 8 MHz with Clock PLL running)
Current Draw @ 3.3 vdc, 70 °F 500 µA per MIPS (MIPS = Freq in MHz / 4 * Number of Active Cogs)
Hardware Connections
Figure 1-1 shows an example wiring diagram that provides host and EEPROM access to the
Propeller chip. In this example the host access is achieved through the Propeller Clip device
(a USB to TTL serial converter).
Figure 1-1: Example wiring diagram that allows for programming the Propeller chip and
an external 32 Kbyte EEPROM, and running the Propeller with an external crystal.
Boot Up Procedure
Upon power-up (+ 100 ms), RESn low-to-high, or software reset:
1. The Propeller chip starts its internal clock in slow mode (≈ 20 KHz), delays for 50 ms
(reset delay), switches the internal clock to fast mode (≈ 12 MHz), and then loads and
runs the built-in Boot Loader program in the first processor (Cog 0).
2. The Boot Loader performs one or more of the following tasks, in order:
a. Detects communication from a host, such as a PC, on pins P30 and P31. If
communication from a host is detected, the Boot Loader converses with the
host to identify the Propeller chip and possibly download a program into
Main RAM and optionally into an external 32 KB EEPROM.
b. If no host communication was detected, the Boot Loader looks for an
external 32 KB EEPROM (24LC256) on pins P28 and P29. If an EEPROM
is detected, the entire 32 KB data image is loaded into the Propeller chip’s
Main RAM.
c. If no EEPROM was detected, the boot loader stops, Cog 0 is terminated, the
Propeller chip goes into shutdown mode, and all I/O pins set to inputs.
3. If either step 2a or 2b was successful in loading a program into the Main RAM, and a
suspend command was not given by the host, then Cog 0 is reloaded with the built-in
Spin Interpreter and the user code is run from Main RAM.
Run-Time Procedure
A Propeller Application is a user program compiled into its binary form and downloaded to
the Propeller chip’s RAM and, possibly, external EEPROM. The application consists of code
written in the Propeller chip’s Spin language (high-level code) with optional Propeller
Assembly language components (low-level code). Code written in the Spin language is
interpreted during run time by a cog running the Spin Interpreter while code written in
Propeller Assembly is run in its pure form directly by a cog. Every Propeller Application
consists of at least a little Spin code and may actually be written entirely in Spin or with
various amounts of Spin and assembly. The Propeller chip’s Spin Interpreter is started in
Step 3 of the Boot Up Procedure, above, to get the application running.
Once the boot-up procedure is complete and an application is running in Cog 0, all further
activity is defined by the application itself. The application has complete control over things
like the internal clock speed, I/O pin usage, configuration registers, and when, what and how
many cogs are running at any given time. All of this is variable at run time, as controlled by
Page 18 · Propeller Manual v1.0
1: Introducing the Propeller Chip
the application, including the internal clock speed. See Chapter 3: Propeller Programming
Tutorial.
Shutdown Procedure
When the Propeller goes into shutdown mode, the internal clock is stopped causing all cogs
to halt and all I/O pins are set to input direction (high impedance). Shutdown mode is
triggered by one of the three following events:
1) VDD falling below the brown-out threshold (≈2.7 vdc), when the brown-out circuit is
enabled,
2) the RESn pin going low, or
3) the application requesting a reboot (see the REBOOT command, page 292).
Shutdown mode is discontinued when the voltage level rises above the brown-out threshold
and the RESn pin is high.
Block Diagram
Figure 1-2: Propeller Chip Block Diagram
Shared Resources
There are two types of shared resources in the Propeller: 1) common, and 2) mutually-
exclusive. Common resources can be accessed at any time by any number of cogs.
Mutually-exclusive resources can also be accessed by any number of cogs, but only by one
cog at a time. The common resources are the I/O pins and the System Counter. All other
shared resources are mutually-exclusive by nature and access to them is controlled by the
Hub. See the Hub section on page 24.
System Clock
The System Clock (shown as “CLOCK” in Figure 1-2) is the central clock source for nearly
every component of the Propeller chip. The System Clock’s signal comes from one of three
possible sources: 1) the Internal RC Oscillator, 2) the Clock Phase-Locked Loop (PLL), or
3) the Crystal Oscillator (an internal circuit that is fed by an external crystal or
crystal/oscillator pack). The source is determined by the CLK register’s settings, which is
selectable at compile time or at run time. The only components that don’t use the System
Clock directly are the Hub and Bus; they divide the System Clock by two (2).
Cogs (processors)
The Propeller contains eight (8) processors, called cogs, numbered 0 to 7. Each cog contains
the same components (see Figure 1-2): a Processor block, local 2 KB RAM configured as 512
longs (512 x 32 bits), two I/O Assistants with PLLs, a Video Generator, I/O Output Register,
I/O Direction Register, and other registers not shown in the diagram. See Table 1-3 for a
complete list of cog registers. Each cog is designed exactly the same and can run tasks
independently from the others.
All eight cogs are driven from the same clock source, the System Clock, so they each
maintain the same time reference and all active cogs execute instructions simultaneously.
See System Clock, above. They also all have access to the same shared resources, like I/O
pins, Main RAM, and the System Counter. See Shared Resources, above.
Cogs can be started and stopped at run time and can be programmed to perform tasks
simultaneously, either independently or with coordination from other cogs through Main
RAM. Regardless of the nature of their use, the Propeller application designer has full
control over how and when each cog is employed; there is no compiler-driven or operating
system-driven splitting of tasks between multiple cogs. This method empowers the developer
to deliver absolutely deterministic timing, power consumption, and response to the embedded
application.
Page 22 · Propeller Manual v1.0
1: Introducing the Propeller Chip
Each cog has its own RAM, called Cog RAM, which contains 512 registers of 32 bits each.
The Cog RAM is all general purpose RAM except for the last 16 registers, which are special
purpose registers, as described in Table 1-3. The Cog RAM is used for executable code, data,
variables, and the last 16 locations serve as interfaces to the System Counter, I/O pins, and
local cog peripherals.
When a cog is booted up, locations 0 ($000) through 495 ($1EF) are loaded sequentially from
Main RAM / ROM and its special purpose locations, 496 ($1F0) through 511 ($1FF) are
cleared to zero. After loading, the cog begins executing instructions, starting at location 0 of
Cog RAM. It will continue to execute code until it is stopped or rebooted by either itself or
another cog, or a reset occurs.
Hub
To maintain system integrity, mutually-exclusive resources must not be accessed by more
than one cog at a time. The Hub maintains this integrity by controlling access to mutually-
exclusive resources, giving each cog a turn to access them in a “round robin” fashion from
Cog 0 through Cog 7 and back to Cog 0 again. The Hub, and the bus it controls, runs at half
the System Clock rate. This means that the Hub gives a cog access to mutually-exclusive
resources once every 16 System Clock cycles. Hub instructions, the Propeller Assembly
instructions that access mutually-exclusive resources, require 7 cycles to execute but they
first need to be synchronized to the start of the Hub Access Window. It takes up to 15 cycles
(16 minus 1, if we just missed it) to synchronize to the Hub Access Window plus 7 cycles to
execute the hub instruction, so hub instructions take from 7 to 22 cycles to complete.
Figure 1-3 and Figure 1-4 show examples where Cog 0 has a hub instruction to execute.
Figure 1-3 shows the best-case scenario; the hub instruction was ready right at the start of that
cog’s access window. The hub instruction executes immediately (7 cycles) leaving an
additional 9 cycles for other instructions before the next Hub Access Window arrives.
Figure 1-4 shows the worst-case scenario; the hub instruction was ready on the cycle right
after the start of Cog 0’s access window; it just barely missed it. The cog waits until the next
Hub Access Window (15 cycles later) then the hub instruction executes (7 cycles) for a total
of 22 cycles for that hub instruction. Again, there are 9 additional cycles after the hub
instruction for other instructions to execute before the next Hub Access Window arrives. To
get the most efficiency out of Propeller Assembly routines that have to frequently access
mutually-exclusive resources, it can be beneficial to interleave non-hub instructions with hub
instructions to lessen the number of cycles waiting for the next Hub Access Window. Since
most Propeller Assembly instructions take 4 clock cycles, two such instructions can be
executed in between otherwise contiguous hub instructions.
Keep in mind that a particular cog’s hub instructions do not, in any way, interfere with other
cogs’ instructions because of the Hub mechanism. Cog 1, for example, may start a hub
instruction during System Clock cycle 2, in both of these examples, possibly overlapping its
execution with that of Cog 0 without any ill effects. Meanwhile, all other cogs can continue
executing non-hub instructions, or awaiting their individual hub access windows regardless of
what the others are doing.
I/O Pins
The Propeller has 32 I/O pins, 28 of which are entirely general purpose. Four I/O pins (28 -
31) have a special purpose at Boot Up and are available for general purpose use afterwards;
see the Boot Up Procedure section on page 18. After boot up, any I/O pins can be used by
any cogs at any time since I/O pins are one of the common resources. It is up to the
application developer to ensure that no two cogs try to use the same I/O pin for different
purposes during run-time.
Each cog has its own 32-bit I/O Direction Register and 32-bit I/O Output Register. The state
of each cog’s Direction Register is OR’d with that of the previous cogs’ Direction Registers.
Similarly, each cog’s output states is OR’d with that of the previous cogs’ output states. Note
that each cog’s output states are made up of the OR’d states of its internal I/O hardware and
that is all AND’d with its Direction Register’s states. The result is that each I/O pin’s
direction and output state is the “wired-OR” of the entire cog collective. No electrical
contention between cogs is possible, yet they can all still access the I/O pins simultaneously!
The result of this I/O pin wiring configuration can easily be described in the following simple
rules:
A. A pin is an input only if no active cog sets it to an output.
B. A pin outputs low only if all active cogs that set it to output also set it to low.
C. A pin outputs high if any active cog sets it to an output and also sets it high.
Table 1-4 demonstrates a few possible combinations of the collective cogs’ influence on a
particular I/O pin, P12 in this example. For simplification, these examples assume that bit 12
of each cog’s I/O hardware, other than its I/O Output Register, is cleared to zero (0).
Example 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Input A
Any cog that is shut down has its Direction Register and output states cleared to zero,
effectively removing it from influencing the final state of the I/O pins that the remaining
active cogs are controlling.
Each cog also has its own 32-bit Input Register. This input register is really a pseudo-
register; every time it is read, the actual states of the I/O pins are read, regardless of their
input or output direction.
System Counter
The System Counter is a global, read-only, 32-bit counter that increments once every System
Clock cycle. Cogs can read the System Counter (via their CNT register, page 184) to perform
timing calculations and can use the WAITCNT command (page 322) to create effective delays
within their processes. The System Counter is a common resource. Every cog can read it
simultaneously. The System Counter is not cleared upon startup since its practical use is for
differential timing. If a cog needs to keep track of time from a specific, fixed moment in
time, it simply needs to read and save the initial counter value at that moment in time, and
compare all of the later counter values against that initial value.
CLK Register
The CLK register is the System Clock configuration control; it determines the source of and
the characteristics for the System Clock. More precisely, the CLK register configures the RC
Oscillator, Clock PLL, Crystal Oscillator, and Clock Selector circuits. (See Figure 1-2:
Propeller Chip Block Diagram on page 20.) It is configured at compile time by the _CLKMODE
declaration and is writable at run time through the CLKSET command. Whenever the CLK
register is written, a global delay of ≈75 µs occurs as the clock source transitions.
Whenever this register is changed, a copy of the value written should be placed in the Clock
Mode value location (which is BYTE[4] in Main RAM) and the resulting master clock
frequency should be written to the Clock Frequency value location (which is LONG[0] in
Main RAM) so that objects which reference this data will have current information for their
timing calculations. (See CLKMODE, page 179, and CLKFREQ, page 175.) When possible, it is
recommended to use the CLKSET command (page 183), since it automatically updates all the
above-mentioned locations with the proper information.
0 Always write ‘0’ here unless you intend to reset the chip.
Same as a hardware reset – reboots the chip. The Spin command REBOOT writes a
1
‘1’ to the RESET bit.
0 1 1 XTALx and PLL1x XIN x 1 OSC+PLL OSCENA and PLLENA must be '1'.
1 0 0 XTALx and PLL2x XIN x 2 OSC+PLL OSCENA and PLLENA must be '1'.
1 0 1 XTALx and PLL4x XIN x 4 OSC+PLL OSCENA and PLLENA must be '1'.
1 1 0 XTALx and PLL8x XIN x 8 OSC+PLL OSCENA and PLLENA must be '1'.
1 1 1 XTALx and PLL16x XIN x 16 OSC+PLL OSCENA and PLLENA must be '1'.
Locks
There are eight lock bits (also known as semaphores) available to facilitate exclusive access
to user-defined resources among multiple cogs. If a block of memory is to be used by two or
more cogs at once and that block consists of more than one long (four bytes), the cogs will
each have to perform multiple reads and writes to retrieve or update that memory block. This
leads to the likely possibility of read/write contention on that memory block where one cog
may be writing while another is reading, resulting in misreads and/or miswrites.
The locks are global bits accessed through the Hub via the Hub Instructions: LOCKNEW,
LOCKRET, LOCKSET, and LOCKCLR. Because locks are accessed only through the Hub, only one
cog at a time can affect them, making this an effective control mechanism. The Hub
maintains an inventory of which locks are in use and their current states, and cogs can check
out, return, set, and clear locks as needed during run time. See LOCKNEW, 230; LOCKRET, 233;
LOCKSET, 234; and LOCKCLR, 228 for more information.
Main Memory
The Main Memory is a block of 64 K bytes (16 K longs) that is accessible by all cogs as a
mutually-exclusive resource through the Hub. It consists of 32 KB of RAM and 32 KB of
Page 30 · Propeller Manual v1.0
1: Introducing the Propeller Chip
ROM. The 32 KB of Main RAM is general purpose and is the destination of a Propeller
Application either downloaded from a host or uploaded from the external 32 KB EEPROM.
The 32 KB of Main ROM contains all the code and data resources vital to the Propeller chip’s
function: character definitions, log, anti-log and sine tables, and the Boot Loader and Spin
Interpreter. The Main Memory organization is shown in Figure 1-5.
Main RAM
The first half of Main Memory is all RAM. This space is used for your program, data,
variables and stack(s); otherwise known as your Propeller Application.
When a program is loaded into the chip, either from a host or from an external EEPROM, this
entire memory space is written. The first 16 locations, $0000 – $000F, hold initialization data
used by the Boot Loader and Interpreter. Your program’s executable code and data will
begin at $0010 and extend for some number of longs. The area after your executable code,
extending to $7FFF, is used as variable and stack space.
There are two values stored in the initialization area that might be of interest to your program:
a long at $0000 contains the initial master clock frequency, in Hertz, and a byte following it
at $0004 contains the initial value written into the CLK register. These two values can be
read/written using their physical addresses (LONG[$0] and BYTE[$4]) and can be read by using
their predefined names (CLKFREQ and CLKMODE). If you change the CLK register without using
the CLOCKSET command, you will also need to update these two locations so that objects which
reference them will have current information.
Propeller Manual v1.0 · Page 31
Introducing the Propeller Chip
Main ROM
The second half of Main Memory is all ROM. This space is used for character definitions,
math functions, and the Boot Loader and Spin Interpreter.
Character Definitions
The first half of ROM is dedicated to a set of 256 character definitions. Each character
definition is 16 pixels wide by 32 pixels tall. These character definitions can be used for
video displays, graphical LCD's, printing, etc. The character set is based on a North
American / Western European layout (Basic Latin and Latin-1 Supplement), with many
specialized characters inserted. The special characters are connecting waveform and
schematic building-blocks, Greek symbols commonly used in electronics, and several arrows
and bullets.
The character definitions are numbered 0 to 255 from left-to-right, top-to-bottom in Figure
1-6, above. In ROM, they are arranged with each pair of adjacent even-odd characters
merged together to form 32 longs. The first character pair is located in bytes $8000-$807F.
The second pair occupies bytes $8080-$80FF, and so on, until the last pair fills $BF80-
$BFFF. The Propeller Tool includes an interactive character chart (Help → View Character
Chart…) that has a ROM Bitmap view which shows where and how each character resides in
ROM.
Page 32 · Propeller Manual v1.0
1: Introducing the Propeller Chip
The character pairs are merged row-by-row such that each character's 16 horizontal pixels are
spaced apart and interleaved with their neighbors' so that the even character takes bits 0, 2, 4,
...30, and the odd character takes bits 1, 3, 5, ...31. The leftmost pixels are in the lowest bits,
while the rightmost pixels are in the highest bits, as shown in Figure 1-7. This forms a long (4
bytes) for each row of pixels in the character pair. 32 such longs, building from the
character’s top row down to the bottom, make up the complete merged-pair definition. The
definitions are encoded in this manner so that a cog’s video hardware can handle the merged
longs directly, using color selection to display either the even or the odd character. It also has
the advantage of allowing run-time character pairs (see next paragraph) that are four-color
characters used to draw beveled buttons, lines and focus indicators.
Some character codes have inescapable meanings, such as 9 for Tab, 10 for Line Feed, and 13
for Carriage Return. These character codes invoke actions and do not equate to static
character definitions. For this reason, their character definitions have been used for special
four-color characters. These four-color characters are used for drawing 3-D box edges at run
time and are implemented as 16 x 16 pixel cells, as opposed to the normal 16 x 32 pixel cells.
They occupy even-odd character pairs 0-1, 8-9, 10-11, and 12-13. Figure 1-8 shows an
example of a button with 3D beveled edges made from some of these characters.
The Propeller Tool includes, and uses, the Parallax True Type® font which follows the design
of the Propeller Font embedded in the hardware. With this font, and the Propeller Tool, you
Sine Table
The sine table provides 2,049 unsigned 16-bit sine samples spanning from 0° to 90°,
inclusively (0.0439° resolution). Sine values for all other quadrants covering > 90° to < 360°
can be calculated from simple transformations on this single-quadrant sine table. The sine
table can be used for calculations related to angular phenomena.
See Appendix B: Accessing Math Function Tables on page 420 for more information.
Concept
The engineering staff at Parallax has used many development environments over a period of
more than 20 years. On many occasions we found ourselves thinking things like:
• It sure would be nice if feature “x” were easier to find/invoke.
• Where are my project files and why are there so many of them?
• Can I legally install/recompile/maintain this on another computer, years from now?
• Isn’t there a less expensive solution?
This experience has driven us to renew our determination to create simple, inexpensive tools
for our products.
The Propeller Tool was designed with those ideas in mind to provide many useful functions
while maintaining a simple, consistent development environment that encourages quick and
easy development of Propeller chip firmware objects.
The Propeller Tool software consists of a single executable file, some on-line help files and
Propeller library files, all stored in the same folder by the installer, typically:
C:\Program Files\Parallax Inc\Propeller. The Propeller Tool’s executable file “Propeller.exe”
can be copied and run from any folder on the computer; it does not rely on special system
files other than what comes standard with the operating system.
Each library file (files with a “.spin” extension) is a self-contained object, available for use by
your Propeller Projects, with both source code and documentation built-in. These are really
just text files, either ANSI- or Unicode-encoded, that may be edited in any text editor that
supports the encoding type; even Notepad in Windows® 2000 (and above) supports both
ANSI and Unicode-encoded text files.
Did you notice we mentioned that an object’s documentation is “built-in” to the object file?
We encourage writing the user documentation for an object right inside the object’s source
┌──┬───┬───┐
220ω │AB│ C │ D │
P1 ───┳───────┳──┐ ├──┼───┼───┤
│ │ │ │00│ 1 │n/a│
0.1µF 50kω ─┘ ├──┼───┼───┤
│ pot │ │01│ 2 │ 5 │
└──┴───┴───┘
After running the Propeller Tool at least once, this font becomes available for other programs
on that computer as well so that you can see these special diagrams using other text editors,
such as Notepad, or even within your email software, provided it supports Unicode-encoded
text (a requirement of the special characters).
Every object you create for your project will also be stored in the same format as library files
(with a “.spin” extension) but in the working directory of your choice. This is all designed to
Screen Organization
The Propeller Tool software’s main window is split into four sections, called “panes,” each
having a specific function.
Panel two displays the modified status of the current edit tab: 1) blank, meaning not modified,
2) modified, or 3) read-only.
Panel three shows the current edit mode: 1) Insert (default), 2) Align, or 3) Overwrite. The
edit mode can be changed by pressing the Insert key. See the Edit Modes section beginning
on page 65 for more information about how the different edit modes work.
Panel four shows the compiled status of the current edit tab: 1) blank, meaning uncompiled,
or 2) compiled. This panel indicates whether or not the source code it represents is still in the
form it was in when it was last compiled. If the code has not been changed in any way since
the last compile operation, this panel will say “Compiled.”
Panel five displays context sensitive information about the current edit tab’s source code if
that code has not been changed since the last compile operation. Move the edit page’s caret
to CON or DAT block symbols or anywhere within PUB/PRI blocks to see information pertaining
to that region.
Panel six displays temporary messages about the most recent operation. This is the area of
the Status Bar where the error message, if any, from the last compile operation is displayed
until another message overwrites it. This area also indicates successful compilations, font
size changes and other status.
The entire Status Bar displays hints describing the function of each menu item on the menu
bar as well as various other items when you let the mouse pointer hover over those items.
Menu Items
File Menu
New Create a new edit tab with a blank page. Any existing edit
tabs are unaffected.
Open… Open a file in a new edit tab with the Open file dialog.
Open From… Open a file in a new edit tab from a recently accessed folder
using the Open file dialog.
Save Save current edit tab’s contents to disk using the existing file
name, if applicable.
Save As… Save current edit tab’s contents to disk with a new file name
using the Save As dialog.
Save To… Save current edit tab’s contents to disk in a recently accessed
folder using the Save As dialog.
Save All Save all unsaved edit tab’s contents to disk using their
existing names, if applicable.
Close Close current edit tab (will prompt if file is unsaved).
Close All Close all edit tabs (will prompt for any files unsaved).
Select Top Object File… Select the top object file of current project. This setting is
used for all of the Compile Top… operations and remains
until changed.
Archive
→ Project… Collect all objects and data files for the project shown in
Object View and store them in a compressed (.zip) file along
with a “readme” file containing archive and structure
information. The compressed file is named after the
project’s top file with “Archive” plus the date/time stamp
appended and is stored in the top file’s work directory.
→ Project + Propeller Tool... Perform the same task as above but add the entire Propeller
Tool executable to the compressed file.
Edit Menu
Undo Undo the last edit action on the current edit page. Each edit
page retains its own undo history buffer until closed.
Multiple undo actions are allowed, limited only by memory.
Redo Redo the last undone action on the current edit page. Each
edit page retains its own redo history buffer until closed.
Multiple redo actions are allowed, limited only by memory.
Cut Delete the selected text from the current edit page and copy
it to the Windows clipboard.
Copy Copy the selected text from the current edit page to the
Windows clipboard.
Paste Paste text from the Windows clipboard to the current edit
page at the current caret position.
Select All Select all text in the current edit page.
Find / Replace… Open the Find/Replace dialog; see Find/Replace Dialog on
page 49 for details.
Find Next Find the next occurrence of the last search string entered into
the Find/Replace dialog.
Replace Replace the current selection with the string entered into the
Replace field of the Find/Replace dialog.
Go To Bookmark Go to bookmark 1, 2, 3… (visible only when bookmarks are
shown).
Run Menu
Compile Current
→ View Info… Compile source code in current edit tab and, if successful,
display Object Info form with the results. The Object Info
form displays many details about the resulting object
including object structure, code size, variable space, free
space and redundancy optimizations.
→ Update Status Compile source code in current edit tab and, if successful,
update the status info on the Status Bar for every object in
the project.
→ Load RAM Compile source code in current edit tab and, if successful,
download the resulting application into Propeller chip’s
RAM and run it.
→ Load EEPROM Compile source code in current edit tab and, if successful,
download the resulting application into Propeller chip’s
EEPROM (and RAM) and run it.
Compile Top
→ View Info… Same as Compile Current → View Info except compilation
is started from the file designated as the “Top Object File.”
→ Update Status Same as Compile Current → Update Status except
compilation is started from the file designated as the “Top
Object File.”
→ Load RAM Same as Compile Current → Load RAM + Run except
compilation is started from the file designated as the “Top
Object File.”
→ Load EEPROM Same as Compile Current → Load EEPROM + Run except
the compilation is started from the file designated as the
“Top Object File.”
Propeller Manual v1.0 · Page 47
Using the Propeller Tool
Identify Hardware… Scan available ports for the Propeller chip and, if found,
display the port it is connected to and the hardware version
number.
Help Menu
Propeller Tool… Display on-line help about the Propeller Tool.
Spin Language… Display on-line help about the Spin language.
Assembly Language… Display on-line help about the Propeller Assembly language.
Example Projects… Display on-line help containing example Propeller Projects.
View Character Chart… Display the interactive Parallax Character Chart. This
character chart shows the Parallax font’s character set in
three possible views: Standard Order, ROM Bitmap and
Symbolic Order. Standard Order is the standard ANSI order.
ROM Bitmap demonstrates how the character data is
organized in the Propeller chip’s ROM. Symbolic Order
lists the characters in a categorical order (i.e.: alpha
characters, numerics, punctuation, schematic symbols, etc).
See Character Chart on page 58.
View Parallax Website… Open up the Parallax website using the computer’s default
web browser.
E-mail Parallax Support… Open up the computer’s default email software and start a
new message to Parallax support.
About… Displays the About window with details about the Propeller
Tool.
Find/Replace Dialog
The Find/Replace dialog is used to find and/or replace text in the current edit page.
Find:
The Find: field is where to enter the string you wish to search for. If a word or phrase was
selected in the current edit page when the Find/Replace dialog was opened, that word or
phrase will automatically be entered in the Find: field. The Find: field remembers the last ten
unique items entered into it. To select a previous entry, click the Find: field’s down arrow
and choose it from the drop-down list.
Replace:
The Replace: field is where to enter the string you wish to replace the found string with. The
Replace: field remembers the last ten unique items entered into it. To select a previous entry,
click the Replace: field’s down arrow and choose it from the drop-down list.
Match
The Match group controls how the string in the Find: field is matched to text in the edit page.
The Match options are: 1) Whole Words, 2) Case, and 3) With Wildcards.
Case
Select the Case checkbox if you want the string in the Find: field to match only text of the
same case; a case-sensitive search.
With Wildcards
Select the With Wildcards checkbox if you want the search to be performed using regular
expression wildcards from the string in the Find: field.
The Origin, Scope and Direction groups all work together to dictate the start, range and
direction the search process should use.
Origin
The Origin group controls where the search begins from; from the Top or from the Cursor.
Selecting Top starts the search from the top of the file (or from the top of the selection if
Selection is set in the Scope group). Selecting Cursor starts the search from the current
cursor (caret) position in the file. Note: The “Top” option changes to “Bottom” if the
Direction group is set to Backward.
Scope
The Scope group controls the range of the search: the Entire File or just the current Selection.
This is a convenient way to perform a find, or a find and replace, within only a limited region
of the file. The Scope group is set to Entire File by default and is disabled unless a selection
is made prior to opening the Find/Replace dialog. The Scope group is set to Selection
automatically if a selection of at least one entire line is made prior to opening the
Find/Replace dialog.
Direction
The Direction group controls the direction of the search; in the Forward direction (towards
the bottom of the file) or the Backward direction (towards the top of the file). If set to
Backward, the Origin group’s first option changes from “Top” to “Bottom,” meaning the
origin is from the bottom of the file or selection.
Replace Button
The Replace button is enabled if a string was entered in the Replace: field and a matching
string was found (via Find button or F3). Clicking Replace, or pressing F4 with or without
the Find/Replace dialog open, causes the currently matched string in the file to be replaced
with the string in the Replace: field. After a replace, the Find Next button, or F3 key, needs
to be used before Replace becomes available again. Holding the Control (Ctrl) key down
changes the Replace button to “Replace/Find” and clicking it, or pressing Ctrl+F4 with or
without the Find/Replace dialog open, causes the currently matched string to be replaced and
then another Find Next operation to be performed immediately.
Close Button
The Close button closes the Find/Replace dialog.
Object View
The Object View displays a hierarchical view of the project you most recently compiled
successfully. There are two Object Views in the Propeller Tool: 1) The Object View at the
top of the Integrated Explorer in the main application’s window (see Pane 1: Object View
Pane on page 39), and 2) The Object Info View in the upper left of the Object Info form (see
Object Info on page 55). Both of these Object Views function in a similar fashion.
The Object View provides visual feedback on the structure of the most recent successful
compilation as well as information for each object within the compiled project.
In Figure 2-9 above, the Object View indicates the structure of the ABC Product application.
In this example, the ABC Product object is the “top object file” (see Objects and
Applications, page 87) and it uses the Numbers, Rotary Encoder and Controller objects.
Additionally, the Controller object uses the TV object.
The object names shown are their actual file names without the extension. The name
includes their file extension only if they are data files (see FILE, page 215) and is shown in
italics as well.
The icons to the left of each object name indicate the folder that the object exists in. This list
shows the four possibilities:
(yellow): Object is within the Work Folder.
(blue) : Object is within the Library Folder.
(striped): Object is in Work Folder but another object with the same name is also
being used from the Library Folder.
(hollow): Object is not in any folder because it has never been saved.
Library Folder
The Library Folder (blue) is where the Propeller Tool’s library objects exist, such as those
that came with the Propeller Tool software. The Library Folder is always the folder that the
Propeller Tool executable started from, and every object (file with .spin extension) within it is
considered to be a library object.
Striped Folders
Objects with striped icons indicate that an object from the work folder and an object from the
library folder each refer to a sub-object of the same name and that sub object happens to exist
in both the work and library folders. This same-named object may be: 1) an exact copy of the
same object, 2) two versions of the same object, or 3) two completely different objects that
just happen to have the same name. Regardless of the situation, it is recommended that you
resolve this potential problem as soon as possible since it may lead to problems later on, such
as not being able to use the Archive feature.
Hollow Folders
Objects with hollow icons indicate that the object was created in the editor and has never
been saved to any folder on the hard drive. This situation, like the one mentioned above, is
not an immediate problem but can lead to future problems if it is not addressed soon.
Using the mouse to point at and select objects can provide additional information as well.
Clicking on an object within the Object View opens that object into the Editor pane. Left-
clicking opens that object in Full Source view, right-clicking opens it in Documentation view
and double-clicking opens it, and all its sub-objects, in Full Source view. If the object was
already open, the Editor pane simply makes the related edit tab active and switches to the
appropriate view; Full Source for a left-click or double-click, or Documentation for a right-
click.
a.
b.
Figure 2-10: Hover the mouse over an object
to see hints with additional information
Figure 2-10b shows the hint for the Numbers object: 1) it’s an object file (i.e.: a sub object,
rather than the top object), 2) it’s in the library folder, and 3) it’s at the path and file name:
C:\Program Files\Parallax Inc\Propeller\Numbers.spin. From this information you can also
infer that the library folder for this project is:
C:\Program Files\Parallax Inc\Propeller.
It’s a good idea to review the hints in the Object View occasionally since they may also
contain additional helpful information, such as warnings about conflicts and optimization
results.
Object Info
The Object Info form displays details about the project you just compiled successfully using
the Compile Current/Top → View Info… function. At the top is an Info Object View very
similar to that of the Integrated Explorer’s Object View (see Object View, p. 52). Below the
Info Object View are two panels with summary information.
Clock Panel
The clock panel, under the RAM Usage panel, displays the clock/oscillator settings of the
object currently selected in the Info Object View. For example, Figure 2-11 shows that the
ABC Product object configured the clock for RCFAST, approximately 12 MHz and no XIN
frequency.
Hex View
The Show/Hide Hex button shows or hides the detailed object hex view, as in Figure 2-12 on
the next page. The hex view shows the actual compiled object data, in hexadecimal, that are
loaded into the Propeller chip’s RAM/EEPROM upon download.
Figure 2-12: Example Object Info Form display with the object Hex View
open showing the hex values of the ABC Product compilation.
The buttons under the hex display allow for downloading and saving of the currently
displayed hex data.
The first two buttons, Load RAM and Load EEPROM, perform the same function as the
similarly named menu items under the Compile Current/Top menu. It’s important to note
that they use the current object (the one selected in the Info Object View) as the source to
download. In other words, you can actually select a sub-object from the project and
download just that; a practical procedure only if that object were designed to run completely
on its own.
The last three buttons, Open File, Save Binary File, and Save EEPROM File, either open a
file or save a file to disk. The Open File button opens a previously saved Binary or EEPROM
file into the Object Info window. The “save” buttons save the hex data from the currently
selected object to a file on disk. Save Binary File saves only the portion actually used by the
object; the program data, but not variable or stack/free space. Save EEPROM File saves the
entire EEPROM image, including variable and stack/free space. Use Save EEPROM File if
you wish to have a file that you can load into an EEPROM programmer for production
purposes.
Character Chart
The Character Chart window is available from the Help → View Character Chart… menu
item. It shows the entire character set for the Parallax Font that is used by the Propeller Tool
and is also built into the ROM of the Propeller chip. There are three views in the Character
Chart: 1) Standard Order, 2) ROM Bitmap, and 3) Symbolic Order.
In each of the three views, the mouse, left mouse button, cursor keys and enter button can be
used to highlight and select a character. If clicked (or enter pressed), the highlighted
character will be entered into the current edit page at the current cursor location. As a new
character is highlighted, the title bar and info bar of the window updates to show the name,
size and address information for that character. Moving the mouse wheel up or down
changes the font size displayed in this window.
Standard Order
Standard Order, shown in Figure 2-13, displays the characters in the order that follows that of
the ANSI set typically used by modern day computers.
ROM Bitmap
The ROM Bitmap, Figure 2-14, shows the characters in a way representative of how they are
stored in the Propeller chip’s ROM. This view uses four colors, white, light gray, dark gray,
and black, to represent the bit pattern of each font character. Each character, in the Propeller
chip’s ROM, is defined with two bits of color (four colors per row in each character cell). The
rows of each pair of adjacent characters are overlapped in memory for the purpose of creating
the run-time characters used to draw 3D buttons with hot key and focus indicators; see
Character Definitions on page 32. The information at the bottom of the window shows the
font size, in points, and the selected character’s pixel data address range in the Propeller
chip’s ROM.
View Modes
Each edit tab can display an object’s source in one of four view modes: 1) Full Source, 2)
Condensed, 3) Summary, and 4) Documentation.
• Full Source view displays every line of source code within the object and is the only
view that supports editing.
• Condensed view hides every line that contains only a code comment as well as
contiguous lines that are blank, showing only compilable lines of code.
• Summary view displays only the block heading lines (CON, VAR, OBJ, PUB, PRI, and
DAT); a convenient way to see the entire object’s structure at a glance.
• Documentation view displays the object’s documentation generated by the compiler
from the source code’s doc comments (see Exercise 3: Output.spin - Comments on
page 100 for more information).
By briefly switching to another view you may be able to locate the routine or region of code
desired. For example, Figure 2-16a shows the Graphics object open in an edit page. If you
were having trouble finding the “plot” routine within the source code, you could switch to the
Summary view (Figure 2-16b) locate the “plot” routine’s header line and click the mouse on
that line to place the cursor there, then switch back to Full Source view (Figure 2-16c). Keep
your eye on the line with the cursor because the code will expand to full view above and
below the line where the cursor is.
The view mode can be changed a number of ways; see the Shortcut Keys listing beginning on
page 75. For example, while in any view mode other than Full Source, pressing the Escape
key will take you back to Full Source view. While in Condensed or Summary view modes,
double-clicking on a line will switch back to Full Source view; expanding above and below
that line. Also, the view mode bar items act like a toggle so that clicking on the Summary
item switches back and forth between Summary view and the previous view mode.
a.
b.
c.
Figure 2-17: Example edit page with Bookmarks enabled and two bookmarks set.
Click on Bookmark Gutter (blank area left of edit page) to set or clear bookmarks.
Press Ctrl+# where # is the desired bookmark number to instantly navigate to an
existing bookmark.
Edit Modes
There are three edit modes provided by the Editor pane: 1) Insert (default), 2) Align
(available for “.spin” objects only), and 3) Overwrite. You can switch between each mode by
using the Insert key. The current mode is reflected by both the caret shape and by panel three
of the status bar.
Figure 2-19: Edit Modes
Insert Edit Mode
Caret is the standard blinking, vertical
bar and the status bar shows “Insert.”
If the original code used tab characters to align the comments, changing “Delay” to
“BtnDelay” will cause a comment to shift right if the altered text crosses a tab boundary.
Figure 2-21: Common Alignment Issues – Tab Aligned
If the original code had been made with tab characters to align the comments,
changing “Delay” to “BtnDelay” results in the second comment suddenly being
pushed out by another tab width.
If the original code had been made with space characters to align the comments,
and a standard Insert edit mode is used, changing “Delay” to “BtnDelay” results in
the second and fifth comments being pushed out by 3 spaces.
For Spin code, the Propeller Tool solves this problem first by disallowing tab characters (Tab
key presses emit the proper number of space characters), and second by providing the Align
edit mode. While in the Align mode, characters inserted into a line affect neighboring
characters but not characters separated by more than one space. The result is that comments
and other items separated by more than one space maintain their intended alignment for as
long as possible, as shown in Figure 2-23.
Using the Align edit mode, changing “Delay” to “BtnDelay” leaves all the comments
in their original, aligned, location. No manual re-aligning of comments is necessary
in this case.
Using the Tab key, this code could have quickly been entered with the following sequence on
the keyboard:
• Type: “PUB FSqr” <Enter>
• Type: <Tab> “repeat 31” <Enter>
• Type: <Tab> “result |= root” <Enter>, etc.
Note that the Enter key automatically aligns the cursor to the level of indention currently in
use; this means the Tab key needs to be pressed only once to indent to the next level.
If there are characters to the right of the cursor when the Tab key is pressed, they are shifted
to the right as well, as in Figure 2-26.
If the cursor is immediately to the left of the first character on a line, both the Shift + Tab and
the Backspace keys cause the cursor and the text to be shifted left to the previous tab position;
i.e.: outdenting. If, however, the cursor is not immediately to the left of the first character on
a line, Backspace acts normally (deleting the previous character) and Shift + Tab moves only
the cursor to the previous tab position.
Multiple Lines
In addition to affecting single lines, multiple lines of code can be indented or outdented to
fixed tab positions easily. Take a look at Figure 2-28.
Suppose we wanted to take the first four lines of this example and encase them in a “repeat
31” loop; to repeat those lines 31 times. You can quickly achieve this with the following
steps: 1) enter the “repeat 31” line above the existing lines, 2) using the mouse, select the four
lines to indent, and 3) press the Tab key. These steps are illustrated in Figure 2-29.
Note that the four lines we had selected in the second step are now indented to the next fixed
tab position (two spaces to the right of the start of the “repeat”) and the selection changed to a
single column surrounding the first characters of the lines. The selection changed to indicate
that we performed a multi-line indention action. Pressing the Tab key again will indent that
group of lines further and pressing Shift + Tab will outdent that group of lines.
Any contiguous group of lines can be indented or outdented in this fashion. The selection
itself doesn’t have to include the entire line either; it only needs to include at least one
character of more than one line to work. This type of selection is called a “stream” selection.
The second type of selection, a “block” selection (see Block Selection and Selection Moving,
page 68), can also be used to indent or outdent portions of lines. For example, Figure 2-30
shows our example with comments to the right of the lines.
If we block select the first few characters of the comments (Alt + Left Mouse Button and
Drag, Figure 2-31), we can press the Tab key to indent those comments to the next fixed tab
position. Pressing Shift + Tab will outdent them, at least up to any characters they bump into
on their left, as in Figure 2-32.
Step 1: Block-select the comment lines (Alt + Left Mouse Button and Drag).
Block-Group Indicators
Sometimes it may be hard to see exactly how groups of code are logically arranged simply by
their level of indention. The Propeller Tool can optionally indicate the logical block-groups
of conditional blocks or loop blocks as shown in Figure 2-32. To toggle this feature on or
off, press Ctrl + I.
Note that only compilable code that is actually within a conditional block or a loop block is
actually enhanced with the indention indicators. Also, this is simply a visual aid to see how
the code will be executed; it does not affect the code or the source file physically; only the
actual levels of indention do that.
Shortcut Keys
Categorical Listings
In Table 2-1, keyboard shortcuts are grouped by related functions. In Table 2-2, which
begins on page 80, the keyboard shortcuts are grouped by key rather than by function.
Table 2-1: Shortcut Keys – Categorical Listing
Tool Shortcuts
Function Keys
New Ctrl + N
Open Ctrl + O
Close Alt + Q -or- Ctrl + W
Save Ctrl + S
Save All Ctrl + Alt + S
Print Ctrl + P
Toggle Show/Hide Bookmarks Ctrl + Shift + B
Toggle Bookmark on current line Ctrl + B
Toggle Block Group Indicators Ctrl + I
Toggle Show/Hide Explorer Ctrl + E
Toggle Show/Hide Line Numbers Ctrl + Shift + N
Increase font size Ctrl + Up -or- Ctrl + Mouse Wheel Up
Decrease font size Ctrl + Down -or- Ctrl + Mouse Wheel Down
Select Full Source view mode Alt + S
Select Condensed view mode Alt + C
Select Summary view mode Alt + U
Select Documentation view mode Alt + D
Select alternate view (towards Full Source) Alt + Up
Select alternate view (towards Documentation) Alt + Down -or- Alt + Mouse Wheel Down
Set focus on active edit Esc
Listing by Key
Table 2-2: Shortcuts By Key
Single Key or Mouse
Function Keys
F2 Rename Folder/File (in Folder List or File List)
F3 Find Next
F4 Replace
F7 Identify Hardware
F8 Compile Current File and View Information
F9 Compile Current File and Update Status
F10 Compile Current File, Load RAM and Run
F11 Compile Current File, Load EEPROM and Run
End Jump to end of line
Esc Select Full Source view mode or set focus on active edit
Home Jump to start of line
Insert Change edit mode to Align (default), Insert or Overwrite
Page Down Scroll down one page size
Page Up Scroll up one page size
Tab Insert white space up to next tab position
Double-Click Select word
Triple-Click Select line
Ctrl + …
Ctrl + A Select All
Ctrl + B Toggle Bookmark on current line
Ctrl + C Copy to Clipboard
Ctrl + E Toggle Show/Hide Explorer
Ctrl + F Find / Replace
Ctrl + I Toggle Block Group Indicators
Concept
The Propeller product (hardware, firmware and software) was designed with many well-
known and also many brand-new concepts in mind. To this end, we designed the hardware,
firmware, software and the two programming languages that go with it (Spin and Propeller
Assembly) completely from scratch to give users the most direct and efficient control over
the Propeller device.
To fully understand and utilize these tools and languages, it is best that you approach it all
with an open mind. In other words, please be careful not to let legacy programming concepts
and methods prevent you from experiencing the advantages made available by the Propeller
chip and its programming languages. We believe that some legacy concepts do not belong in
true real-time processing environments since they tend to bring turmoil to those who rely on
them.
Propeller Objects
The Propeller chip’s Spin language is object-based and serves as the foundation for every
Propeller Application.
What is an Object?
Objects are really just programs written in a way that: 1) create a self-contained entity, 2)
perform a specific task, and 3) may be reused by many applications.
For example, the Keyboard object and Mouse object each come with the Propeller Tool
software. The Keyboard object is a program that interfaces the Propeller chip to a standard
PC-style keyboard. Similarly, the Mouse object interfaces to a standard computer mouse.
Both of these objects are self-contained programs with carefully designed software interfaces
that allow other objects, and developers, to use them easily.
Propeller Object
Spin Code
Objects are stored on your computer as files with “.spin” extensions, therefore you should
always think of each Spin file as an object.
Figure 3-2: Object Files consist of Spin, and possibly Propeller Assembly, and are
stored as “.spin” files on your computer’s hard drive.
Each object can be thought of as a “building block” for an application. An object may choose
to utilize one or more other objects in order to build a more sophisticated application. This is
loosely called “referencing” or “including” another object. When an object references other
objects it forms a hierarchy where it is the object at the top, as in Figure 3-3. The topmost
object is referred to as the “Top Object File” and is the starting point for compiling a
Propeller Application.
In the above figure, the Graphics Demo object references three other objects: TV, Graphics,
and Mouse. If the Graphics Demo object is compiled by the user, it is considered the Top
Page 88 · Propeller Manual v1.0
3: Propeller Programming Tutorial
Object File and the other three objects are loaded and compiled with it resulting in a finished
program called a Propeller Application, or “application” for short.
Applications are formed from one or more objects. The application is really a specially
compiled binary stream that consists of executable code and data and can be run by the
Propeller chip.
When downloaded, the application is stored in the Propeller chip’s Main RAM and optionally
into an external EEPROM. At run time, the application is executed by one or more of the
Propeller chip’s processors, called cogs, as directed by the application itself.
Figure 3-4:
Downloading
Applications
consisting of one
or more objects are
downloaded to the
Propeller chip’s
RAM, and
optionally, its
external EEPROM.
If you have made the connections suggested above, you should be able to verify and identify
the Propeller chip via the Propeller Tool software. Start the Propeller Tool software (Version
1.0) and then press the F7 key (or select Run → Identify Hardware… from the menu). If the
Page 90 · Propeller Manual v1.0
3: Propeller Programming Tutorial
Propeller chip is powered and connected to the PC properly, you should see an “Information”
dialog similar to Figure 3-6.
PUB Toggle
dira[16]~~
repeat
!outa[16]
waitcnt(3_000_000 + cnt)
While indentation is critical, capitalization is not. Propeller code is not case-senitive.
However, throughout this book, reserved words appear in bold all-captials, except in code
snippets and excerpts, to help you become familiar with them.
After checking that you’ve typed it in properly, press the F10 key (or select Run → Compile
Current → Load RAM + Run from the menu) to compile and download our example
program. If the program you entered is syntactically correct and the Propeller chip is
properly powered and connected to the PC, you should see a “Propeller Communication”
dialog appear momentarily on the screen, like the one in Figure 3-7, and now the LED on I/O
pin 16 of the Propeller chip should be blinking about twice per second. What we just
accomplished is what is shown at the top of Figure 3-4: Downloading on page 89.
What really happened was probably too fast to see because the example program we entered
is so small. When you pressed F10 it caused the Propeller Tool to compile the source code
you entered and turn it into a Propeller Application. The Propeller Tool then searched for a
Propeller chip connected to the PC and downloaded the application into its RAM. Finally,
the Propeller started running the application from RAM, blinking the LED on I/O pin 16.
PUB Toggle
dira[16]~~
repeat
!outa[16]
waitcnt(3_000_000 + cnt)
The first line, PUB Toggle, declares that we’re creating a “public” method called “Toggle.” A
method is the object-oriented term for “procedure” or “routine.” We chose the name Toggle
simply because it is descriptive of what the method does and we knew it is a unique symbol;
it must be a unique symbol and conform to the Symbol Rules on page 159. We’ll describe
the term PUB, “public,” in more detail later, but it’s important to note that every object must
contain at least one public (PUB) method.
The rest of the code is logically part of the Toggle method. We indented each line by two
spaces from the PUB’s column to make that more clear; this indenting isn’t required but is a
good habit for clarity.
The first line of the Toggle method (second line of our example), dira[16]~~, sets the
direction of I/O pin 16 to output. The DIRA symbol is the direction register for I/O pins P0
through P31; clearing or setting bits within it changes the corresponding I/O pin’s direction to
input or output. The [16] following dira indicates we want to access only the direction
register’s bit 16; the one that corresponds to I/O pin 16. Finally, the ~~ is the Post-Set
operator that causes direction register bit 16 to be set to high (1); which makes I/O pin 16’s
direction an output. The Post-Set operator is a shorthand way of saying something like
dira[16] := 1 which may look familiar to you from other languages.
The next line, repeat, creates a loop consisting of the two lines of code below it. This REPEAT
loop runs infinitely, toggling P16, waiting ¼ second, toggling P16, waiting ¼ second, etc.
The next line, !outa[16], toggles the state of I/O pin 16 between high (VDD) and low (VSS).
The OUTA symbol is the output state register for I/O pins P0 through P31. The [16] in
!outa[16] indicates we want to access only the output register’s bit 16; the one that
corresponds to I/O pin 16. The ! at the start of this statement is the Bitwise Not operator; it
toggles the state of all bits specified to its right (the bit corresponding to I/O pin 16 in this
case).
The last line, waitcnt(3_000_000 + cnt), causes a delay of 3 million clock cycles. WAITCNT
means “Wait for System Counter.” The cnt symbol is the System Counter register; CNT
If you haven’t saved this example object yet, you may do so by pressing Ctrl+S (or selecting
File → Save from the menu). You may save it in a folder of your choosing but make sure to
save it with the filename “Output.spin” since some exercises below rely on it.
Quick Review: Ex 1
• Applications are downloaded to either Propeller RAM only or RAM and EEPROM.
o Those in RAM will not survive power cycling or resetting the Propeller chip.
o Those in EEPROM are loaded into RAM on boot-up in approximately 1½
seconds.
o To download the current object to:
RAM only: press F10 or select Run → Compile Current → Load
RAM + Run.
RAM + EEPROM: press F11 or select Run → Compile Current →
Load EEPROM + Run.
• Spin language:
o Method means “procedure” or “routine.”
o PUB Symbol declares a public method called Symbol. Every object must
contain at least one public (PUB) method. See PUB on page 287 and Symbol
Rules on page 159.
o DIRA is the direction register for I/O pins 0-31. Each bit sets the
corresponding I/O pin’s direction to input (0) or output (1). See DIRA, DIRB
on page 212.
o OUTA is the output state register for I/O pins 0-31. Each bit sets the
corresponding I/O pin’s output state to low (0) or high (1). See OUTA, OUTB
on page 280.
o Registers can use indexes, like [16], to access individual bits within them.
See DIRA, DIRB on page 212 or OUTA, OUTB on page 280.
o ~~ following a register/variable sets its bit(s) high. See Sign-Extend 15 or
Post-Set ‘~~’ on page 263 in the Operators section.
o ! preceding a value/register/variable sets its bit(s) opposite their current state.
See Bitwise NOT ‘!’on page 272 in the Operators section.
o REPEAT creates a loop structure. See REPEAT on page 293.
o WAITCNT creates a delay. See WAITCNT on page 322.
o Indention at the start of lines:
indicates they belong to the preceding structure; it is required for
lines following conditional or loop commands (like REPEAT).
(Indenting is optional after block indicators, such as PUB.)
Ctrl+I toggles visible block-group “structure” indicators on and off.
Cogs (Processors)
The Propeller has eight identical processors, called cogs. Each cog can be individually set to
run or stop at any time as directed by the application it is running. Each cog can be
programmed to run independent tasks or cooperative tasks with other cogs, as needed, and
this can change as desired during the application’s run time.
But we didn’t specify which cog(s) to run in our Output.spin example, so how did it work?
For a review, you could read Boot Up Procedure, page 18, and Run-Time Procedure, page 18,
in Chapter 1, but we’ll discuss it a bit more here.
For our example, upon power-up, the Propeller chip starts the first processor (Cog 0) and
loads it with a built-in Boot Loader program. The Boot Loader program is copied from the
Propeller chip’s ROM into Cog 0’s internal RAM memory. Cog 0 then runs the Boot Loader
program in its internal memory and the Boot Loader soon determines it should copy user-
code from the external EEPROM. So Cog 0 copies the entire 32 K byte EEPROM contents
into the Propeller chip’s 32 K byte main RAM memory (separate from the cog’s internal
memory). Then the Boot Loader program makes Cog 0 reload itself with the built-in Spin
Interpreter; the Boot Loader program in Cog 0 halts at this point while it is being overwritten
with the Spin Interpreter program.
RAM
RAM
RAM
RAM
Cog 1
Cog 2
Cog 7
Now, Cog 0 is running the Spin Interpreter, which fetches and executes our application’s
code from main memory (RAM). This is shown in Figure 3-9. Since our application consists
Propeller Manual v1.0 · Page 97
Propeller Programming Tutorial
entirely of interpreted Spin code, it continues to reside only in main memory while a cog
running the Spin Interpreter (Cog 0 in this case) reads, interprets and effectively executes it.
No other cogs were started during boot up or during our application’s execution; the other
seven cogs remain in a dormant state consuming virtually no current at all. Later, we’ll
change our application to start other cogs as well.
CON
Pin = 16
Delay = 3_000_000
PUB Toggle
dira[Pin]~~
repeat
!outa[Pin]
waitcnt(Delay + cnt)
The new CON block at the top of the code defines global constants for the object (see CON,
page 194.) In it, we created two symbols, Pin and Delay, and assigned the constant values 16
and 3,000,000 to them, respectively. We can now use the symbols Pin and Delay elsewhere
in the code to represent our constant values 16 and 3,000,000. Notice that we used
underscores ( _ ) to separate the “thousands” groups in the number 3,000,000? Commas are
not allowed there but underscores are allowed anywhere inside of constant values; this makes
large numbers more readable.
In the Toggle method, we replaced both occurrences of 16 with the symbol Pin, and replaced
the 3_000_000 with the symbol Delay. When compiled, the Propeller Tool will use the
constant values in place of their respective symbols. This makes it easy, later on, to change
the pin number or delay at will since we only have to change it up at the top of code in a
place that is easy to find and understand.
Try changing the Delay constant from 3,000,000 to 500,000 and download again; the LED
should now flicker at a rate of 12 blinks per second (24 toggles per second). You can also
Block Designators
You may have noticed that the backgrounds of the CON and PUB blocks of code were colored
differently when you entered them into the editor. This is the Propeller Tool’s way to
indicate these are distinct blocks of code.
Spin code is organized in blocks that have distinct purposes. CON and PUB are block
designators that indicate the start of a “constant block” and “public method block”,
respectively. Every block designator must start in the first column of text (the leftmost edge
of the edit pane) on a line. There are six types of blocks in the Spin language: CON, VAR, OBJ,
PUB, PRI, and DAT. The following is a list of the block designators and their purpose:
CON Global Constant Block. Defines symbolic constants that can be used anywhere
within the object (and in some cases outside the object) wherever numeric values
are allowed.
VAR Global Variable Block. Defines symbolic variables that can be used anywhere
within the object wherever variables are allowed.
OBJ Object Reference Block. Defines symbolic references to other existing objects.
These are used to access those objects and the methods and constants within
them.
PUB Public Method Block. Public methods are code routines that are accessible both
inside and outside the object. Public routines provide the interface to the object;
the way methods outside of the object interact with the object. There must be at
least one PUB declaration in every object.
PRI Private Method Block. Private methods are code routines that are accessible only
inside the object. Since they are not visible from the outside, they provide a level
of encapsulation to protect critical elements within the object and help maintain
the integrity of the object’s purpose.
DAT Data Block. Defines data tables, memory buffers, and Propeller Assembly code.
The data block’s data can be assigned symbolic names and can be accessed via
Spin code and assembly code.
There can be multiple occurrences of each block type, arranged in any order desired, but there
must be at least one PUB block per object. Even though the number of blocks and their order
Propeller Manual v1.0 · Page 99
Propeller Programming Tutorial
is quite flexible, typically there is only one occurrence of CON, VAR, OBJ and DAT blocks,
multiple occurrences of PUB and PRI blocks, and the suggested order for typical programs is
the order they are given in the list above.
The very first PUB block in the very first object (the Top Object File where compilation starts
from) automatically becomes the Propeller Application’s starting point; it is executed first
when the application starts. No other public or private method is executed automatically, but
rather they are executed only as determined by the natural flow of the application.
The Propeller Tool automatically colors the backgrounds of each block differently, even two
consecutive occurrences of the same block type, in order to make it easy to identify the type,
start, and end of each block. This in no way affects the actual source code itself, it is simply
an indicator for on-screen use that is intended to solve a typical problem with source code;
that is, as the code gets larger, it is harder to find a particular method quickly as you scroll up
and down through the code unless you have some kind of separator between methods. The
background color coding serves as an automatic separator that prevents you from having to
waste time typing in text-based separators manually.
CON
Pin = 16 { I/O pin to toggle on/off }
Delay = 3_000_000 { On/Off Delay, in clock cycles}
PUB Toggle
''Toggle Pin forever
{Toggles I/O pin given by Pin and waits Delay system clock cycles
in between each toggle.}
PUB Toggle
Program: 8 Longs
Variable: 0 Longs
PUB Toggle
If you compare this to our code you should recognize all the text that came directly from our
document comments. The section “Object "Output" Interface:” is created automatically by
the Propeller Tool; it lists all the public methods (just PUB Toggle in this case) and shows that
the program size is 8 longs (32 bytes) and no variables were used. Following that, it lists all
the public methods again, with an overbar above each method, and the document comments
that belong with them. This section shows the public Toggle method and our last document
comment, “Toggle Pin forever,” indicating what the Toggle method does.
Adding document comments to your code allows you to create just one file that contains both
source code and documentation for an object. This is extremely convenient for developers
since they can easily switch to Documentation view to learn how to use an object they are
unfamiliar with. To support this further, the Propeller Tool’s Parallax font has many special
characters for including schematics, timing diagrams, and mathematical symbols right in the
objects that they relate to, like those shown in Figure 2-1 on page 36.
{{Output.spin
CON
Pin = 16 { I/O pin to toggle on/off }
Delay = 3_000_000 { On/Off Delay, in clock cycles}
PUB Main
Toggle(16, 3_000_000, 10) 'Toggle P16 ten times, 1/4 s each
Toggle(17, 2_000_000, 20) 'Toggle P17 twenty times, 1/6 s each
{{Output.spin
Toggle two pins, one after another simultaneously.}}
VAR
long Stack[9] 'Stack space for new cog
PUB Main
cognew(Toggle(16, 3_000_000, 10), @Stack) 'Toggle P16 ten…
Toggle(17, 2_000_000, 20) 'Toggle P17 twenty…
RAM
RAM
RAM
Cogs Running Output
... Application and
Toggle method.
Cog 0
Cog 1
Cog 2
Cog 7
Notice that the Spin
Interpreter is loaded
Interpreter ROM
into each Cog’s RAM.
Main RAM
The Spin Application,
Output, resides in
Spin Code Main RAM interpreted
Application by Cog 0 and it
launches Cog 1 to run
just the Toggle
method.
{{ Output.spin }}
Toggle two pins, one after another.}}
VAR
long Stack[9] 'Stack space for new cog
PUB Main
cognew(Toggle(16, 3_000_000, 10), @Stack) 'Toggle P16 ten…
Toggle(17, 2_000_000, 20) 'Toggle P17 twenty…
OBJ
LED : "Output"
PUB Main
{Toggle pins at different rates, simultaneously}
LED.Start(16, 3_000_000, 10)
LED.Toggle(17, 2_000_000, 20)
Save this new object as “Blinker1.spin” in the same folder as you saved Output.spin. Now,
with Blinker1’s edit tab active, press F10 to compile and download. The LEDs should have
blinked in the same way they did in Exercise 5, but a different technique was used by the
code; Blinker1 used our Output object and simply called Output’s Start and Toggle methods.
Here’s how it worked. In Blinker1 we have an object block (OBJ) and a public method (PUB).
The object block’s LED : "Output" line declares that we’re going to use another object called
Output and that we’ll refer to it as LED within this Blinker1 object.
The Object-Method Reference
In the public method, Main, we have two method calls. Remember how we learned in
Exercise 4 that one method can call another just by referencing its name? That works for
methods that are in the same object, but now we need to call a method that is in another
object. To do this, we use the form object . method where object is the symbolic name we
Propeller Manual v1.0 · Page 111
Propeller Programming Tutorial
gave the object in the OBJ block (LED in this case) and method is the name of that object’s
method. This is called an Object-Method reference. Blinker1 refers to the Output object as
LED, so LED.Start calls Output’s Start method, and LED.Toggle calls Output’s Toggle
method.
When Blinker1 is compiled, since it references Output, the two objects get compiled into one
application. Figure 3-11 illustrates this. This structure is also shown in the Object View,
which we’ll learn about next.
Each menu, Compile Current and Compile Top, has the same sub-options but they start their
compilation from different places. Compile Current starts from the active edit tab and
Compile Top starts from the designated Top Object File.
You can tell the Propeller Tool which object to treat as the “designated Top Object File” at
any time. You do this by any one of the following methods:
1) Right-click the desired object’s edit tab and select “Top Object File,” or
2) Right-click the desired object from the File List (in the Integrated Explorer) and
select “Top Object File,” or
3) Choose the File → Select Top Object File… menu option and select the desired file
from the browse window, or
4) Press Ctrl+T and select the desired file from the browse window.
We used option #1 to select Blinker1 as the Top Object File, in the figure below. Note that
afterwards, the Blinker1 tab’s text is bold; see Figure 3-14b. The file the Propeller Tool
knows as the Top Object File always appears in bold.
Now, if we use one of the Compile Top options, such as Ctrl+F10 or Ctrl+F11, regardless of
which edit tab is active, the Propeller Tool will compile starting from the Top Object File.
For example, in Figure 3-14b the Output object is the active edit tab. If we press Ctrl+F10,
the application will be compiled starting with the Blinker1 object, however. If we had
pressed F10 instead, the Output object would have been compiled.
Each of the shortcut keys for the Compile Current options, F8, F9, F10, etc., has a similar
variation for the Compile Top options, Ctrl+F8, Ctrl+F9, Ctrl+10, etc.
a.
b.
{{ Output.spin }}
VAR
long Stack[9] 'Stack space for new cog
byte Cog 'Hold ID of cog in use, if any
Stop
Success := (Cog := cognew(Toggle(Pin, Delay, Count), @Stack) + 1)
PUB Stop
{{Stop toggling process, if any.}}
if Cog
cogstop(Cog~ - 1)
Quick Review: Ex 7
• Objects:
o Have no direct relationship with cogs.
o Should call interface methods “Start” and “Stop” if they affect other cogs.
o Should call interface method “Init” if it needs initialization.
• Spin language:
o Variables defined in variable blocks are global to the object so modifications
by one method are visible by other methods. See VAR, page 315.
o Booleans: (See Constants (pre-defined), page 202 and Operators, page 249).
FALSE = 0
TRUE = -1; any non-zero (≠0) value is True for Boolean comparisons.
o Compound expressions can include Intermediate Assignments, see page 253.
o Operators:
“Pre”/“Post” operators perform their duty before/after the variable’s
value is used by the expression.
Assignment ‘:=’ is similar to equal ‘=’ in other languages, see
Variable Assignment ‘:=’, page 255.
Post-Clear ‘~’ clears the variable preceding it to zero (0), see Sign-
Extend 7 or Post-Clear ‘~’, page 262.
Pre-Decrement ‘--’ decrements the variable following it, giving the
expression the result, see Decrement, pre- or post- ‘- -’, page 257.
Is Greater Than ‘>’ returns True if value on left-side is greater than
that of right-side, see Boolean Is Greater Than ‘>’, ‘>=’, page 276.
Limit Minimum ‘#>’ returns the greater of either the value on its left
or its right, see Limit Minimum ‘#>’, ‘#>=’, page 260.
o Methods: (See PUB, page 287).
Always return a long value (4 bytes) whether or not one is specified.
Contain a built-in local variable, RESULT, that holds its return value.
Return values are declared by following the method’s name and
parameters with a colon (:) and a descriptive return value name.
o COGNEW returns the ID (0 to 7) of cog started; -1 if none, see COGNEW, page 189.
o COGSTOP deactivates a cog by ID, see COGSTOP, page 193.
o IF is a conditional structure that executes the indented block of code
following it if the conditional statement is true, see IF, page 220.
o REPEAT’s conditional, one-to-many form: REPEAT WHILE Condition executes at
least once and continue while Condition is true. See REPEAT, page 293.
• The Propeller Tool bolds matching parentheses pairs surrounding the cursor.
CON
MAXLEDS = 6 'Number of LED objects to use
OBJ
LED[6] : "Output"
PUB Main
{Toggle pins at different rates, simultaneously}
repeat
repeat Index from 0 to MAXLEDS-1
if not LED[Index].Active
quit
while Index == MAXLEDS
Page 124 · Propeller Manual v1.0
3: Propeller Programming Tutorial
Compile and download Blinker2. You should see six LEDs start blinking with different,
independent, rates and periods. Look carefully, after about 8 seconds P20 will stop blinking
and P22 will start. A few seconds later, P18 will stop and P23 will start, then P16 will stop
and P20 will start again, but at a different rate. Eventually, all but P17 and P20 will cease.
Can you figure out why it behaves this way? We’ll explain it below.
Figure 3-16:
Blinker2 Application
Does this mean our application grew by the size of the Output object times six? Fortunately,
the answer is no. The Propeller Tool optimizes the application’s code such that, for every
occurrence of an object only one copy of the object’s code is included, but multiple copies of
the object’s global variables are created. This is because the code is considered to be static
(unchanging) and exactly the same for each object. However, the object’s global variables
(defined in its VAR block), are not static; each object needs its own variable space in order to
work independently without interference from other instances of itself.
Figure 3-17:
Object Info Window
for Blinker2
Application
Object Lifetime
When applications are compiled a binary image of the executable code is created. That
binary image is what is actually downloaded into the Propeller and is usually what we are
referring to when we say “application” or “Propeller Application.”
The compiled code for each object used by an application is included within that binary
image along with variable space for each instance of each of those objects.
During run time, the application may use any object for any amount of time; some may be
used always and others only on occasion but all are consuming a static amount of memory for
their code and variables.
For developers accustomed to programming with objects on a computer, this is an important
concept to understand. On the Propeller an object’s lifetime is static; whether or not it is
actively in use at the time, it always requires a specific amount of memory in the
application’s binary image. On desktop/laptop computers, objects require a dynamic amount
of memory because they are “created” and “destroyed” during the run-time process as is
needed. On the Propeller, the objects are “created” at compile time and are never “created”
or “destroyed” at run time because the act of doing so would fragment memory and cause
indeterministic behaviour in real-time embedded systems.
Quick Review: Ex 8
• Applications:
o Use unique symbols, or elements of an array, for each distinct object in use.
o Use one copy of an object’s code and one or more copies of its global
variables.
• Objects:
o An object array may be created in object blocks similar to a variable array in
variable blocks.
o An object’s lifetime is static, consuming a specific, static amount of memory
regardless of whether or not it is active. This eliminates the possibility of
fragmented memory during normal run-time use and ensures deterministic
behavior in real-time systems.
• Spin language:
o REPEAT command: (See REPEAT, page 293).
Finite, counted loop: REPEAT Variable FROM Start TO Finish where
Variable is the variable to use as the counter and Start and Finish
indicate the range.
The QUIT command works inside REPEAT loops only and causes the
loop to terminate immediately, see QUIT, page 291.
o I/O registers (DIRx, OUTx, and INx) may use the form reg[a..b] to affect
multiple contiguous pins; where reg is the register (DIRx, OUTx, or INx) and a
and b are I/O pin numbers, see DIRA, DIRB on page 212, OUTA, OUTB on page
280, and INA, INB on page 225.
• I/O pins are set to outputs only while a cog that set them that way remains active, see
DIRA, DIRB, page 212.
• Compile & View Info: F8 key (or select Run → Compile Current → View Info…),
see Object Info, page 55.
CON
_CLKMODE = RCSLOW 'Set to internal slow clock
MAXLEDS = 6 'Number of LED objects to use
Try compiling and downloading Blinker2 now. Once the Propeller finishes the
download/boot-up process, it switches to the RCSLOW clock mode and executes the application.
Since the application is now running with a clock that is hundreds of times slower that before,
the application will run much slower, taking more than 20 seconds for the fastest toggling
pin, P20, to toggle off for the first time.
You can replace _CLKMODE = RCSLOW with _CLKMODE = RCFAST to have the application run with
the internal fast clock (the default).
If you’d like to use an external clock, there are many more options for _CLKMODE. We’ll
assume you’re using a 5 MHz external crystal, like the one that comes with the Propeller
Demo Board.
CON
_CLKMODE = RCSLOW 'Set to internal slow clock
_CLKMODE = XTAL1 'Set to ext. low-speed crystal
_XINFREQ = 5_000_000 'Frequency on XIN pin is 5 MHz
MAXLEDS = 6 'Number of LED objects to use
Here we set _CLKMODE to XTAL1 which configures the clock mode for an external low-speed
crystal and configures the Propeller internal oscillator gain circuitry to drive a 4 MHz to 16
MHz crystal. Besides the crystal itself (which should be connected to the XI and XO pins),
no other external circuitry is required for this clock configuration.
Whenever external crystals or clocks are used, either _XINFREQ or _CLKFREQ must be specified
in addition to _CLKMODE. _XINFREQ specifies the frequency coming into the XI pin (Crystal
Input pin). _CLKFREQ specifies the System Clock frequency. The two are related by PLL
settings which we’ll discuss later.
In this example we specified an _XINFREQ value of 5 million to indicate that the frequency on
the XI pin is 5 MHz, since we have a 5 MHz crystal connected to XI and XO. Once that is
specified, the _CLKFREQ value is automatically calculated and set by the Propeller Tool.
You could also have specified a _CLKFREQ of 5 MHz (instead of _XINFREQ) and the proper
_XINFREQ value would automatically be set by the Propeller Tool. However, it is more typical
to specify the _XINFREQ value since _CLKFREQ is directly affected by PLL settings. In our
example, both _XINFREQ and _CLKFREQ end up with the same value, but a later example will
show how they can typically differ.
If you compile and download Blinker2 now, you should see the LEDs toggle at slightly less
than half the speed as in Exercise 8. Our settings specified an external 5 MHz crystal instead
of the internal 12 MHz oscillator.
So why would anyone want to use an external crystal that is slower than the internal clock?
Two reasons: 1) for accuracy; the internal clock is not very accurate from chip to chip or
across voltage variances but external crystals or clock/oscillators are typically very accurate,
and 2) the phase-locked loop (PLL) can only be used with external clock sources.
Try the following example:
CON
_CLKMODE = XTAL1 + PLL4X 'Set to ext low-speed crystal, 4x PLL
_XINFREQ = 5_000_000 'Frequency on XIN pin is 5 MHz
MAXLEDS = 6 'Number of LED objects to use
Here we changed the _CLKMODE setting slightly by adding the + PLL4X value. This configures
the clock mode to use the internal phase-locked loop (PLL) to wind up the XIN frequency by
four times, resulting in a System Clock frequency of 5 MHz * 4 = 20 MHz.
Try compiling and downloading Blinker2 with these settings. You should see the LEDs blink
at a faster rate than you’ve seen before.
NOTE: Since we specified _XINFREQ here, _CLKFREQ is automatically calculated to be 20 MHz.
If we had specified a _CLKFREQ value of 5 MHz instead, adding the PLL4X setting would have
calculated an _XINFREQ value of 1.25 MHz, which doesn’t match our external crystal’s
frequency. This is why it is more common to specify an XIN frequency (_XINFREQ) rather
than a clock frequency (_CLKFREQ).
The Clock PLL circuit, when enabled, always winds up the frequency by 16 times, but you
can select any of the 1x, 2x, …16x taps for the final System Clock frequency using the
settings PLL1X, PLL2X, PLL4X, PLL8X and PLL16X.
Try changing _CLKMODE from XTAL1 + PLL4x to XTAL1 + PLL16x and download again. That
configures the System Clock to be 5 MHz * 16 = 80 MHz! Most of the LEDs blink so
quickly that they appear to be solidly on.
{{ Output.spin }}
VAR
long Stack[9] 'Stack space for new cog
byte Cog 'Hold ID of cog in use, if any
Stop
Success := (Cog := cognew(Toggle(Pin, DelayMS, Count), @Stack) + 1)
PUB Stop
{{Stop toggling process, if any.}}
if Cog
cogstop(Cog~ - 1)
{{ Blinker2.spin }}
CON
_CLKMODE = XTAL1 + PLL4X 'Set to ext low-speed crystal, 4x PLL
_XINFREQ = 5_000_000 'Frequency on XIN pin is 5 MHz
MAXLEDS = 6 'Number of LED objects to use
OBJ
LED[6] : "Output"
PUB Main
{Toggle pins at different rates, simultaneously}
repeat
repeat Index from 0 to MAXLEDS-1
if not LED[Index].Active
quit
while Index == MAXLEDS
Select “Propeller
Library” from the
Integrated Explorer’s
Recent Folders list to
quickly browse to the
library folder.
Let’s use some of them now. Create a new file and enter the code below. The highlighted
items are important for the discussion following the code.
{{ Display.spin }}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
OBJ
Num : "Numbers"
TV : "TV_Terminal"
Look at what we just achieved! Using just a few lines of our own code plus two existing
library objects and three resistors (on the Propeller Demo Board) we converted numeric
values to text strings and generated a TV-compatible signal to display that text in real time on
a standard TV! In fact, while you are reading this, a cog is keeping busy constantly
generating an NTSC signal at 60 frames per second that the TV can lock onto.
The TV_Terminal object provides a great display for debugging purposes. Since the
Propeller has many processors and can run quite fast, a real-time display such as a TV
monitor (CRT or LCD) used for debugging purposes goes a long way toward developing
optimal source code. We recommend using this technique along with the usual debugging
techniques to speed up development time.
Let’s look at some important parts of our code now. The first new item in our code is the
| Temp that appears in Main’s declaration line. Don’t be fooled, this may look like a return
variable declaration, but it is not. The pipe symbol ‘|’ indicates we are declaring local
variables next. So, | Temp declares that Temp is a long-sized local variable for Main.
Next we have two very important statements, Num.Init and TV.Start(12). These two
statements initialize the Numbers object and start the TV_Terminal object (on pins 12, 13 and
14), respectively. Each of these objects requires some kind of initialization before using it.
Numbers requires that its Init method is called to initialize some internal registers.
TV_Terminal requires that its Start method is called to configure the proper output pins and
to start two more cogs to generate the display signals. Objects typically indicate these
requirements in their documentation, but it is common that they include an Init or a Start
method if they require some initial setup before use.
The next line performs some arithmetic and sets our local variable, Temp, to the result. We’ll
use this result soon.
The next three statements create the first line of text on the TV display:
9 * 45 + 401 = 40,901. The TV.Str method outputs a zero-terminated string to the display.
Its parameter, string("900 * 45 + 401 = ") is new to us. STRING is a directive that creates a
zero-terminated string of characters (multiple bytes of character data followed by a zero;
sometimes called a z-string) and returns the address of that string. Most methods that deal
with strings require just the address of the starting character and for the string to end with a
byte equal to zero. TV.Str method’s parameter requires exactly that, the address of a zero-
Page 140 · Propeller Manual v1.0
3: Propeller Programming Tutorial
terminated string. So the line TV.Str(string("900 * 45 + 401 = ")) causes the string “900
* 45 + 401 = ” to be displayed on the TV.
The next statement, TV.Str(Num.ToStr(Temp, Num#DDEC)) prints the “40,901” part of the line.
The Num.ToStr method converts the numeric value in Temp into a string using delimited
decimal format and returns the address of that string. Temp, of course, holds the long-sized
result of our earlier expression: 40901. The Num#DDEC part is new to us, however. The #
symbol when used this way is an Object-Constant reference; it is used to reference a constant
that was defined in another object. In this case, Num#DDEC refers to the “format constant” DDEC
that is declared within the Numbers object. As defined by Numbers, DDEC stands for
Delimited Decimal and holds a value that indicates to the ToStr method that it should format
the number with a thousands-group delimiter; a comma in this case. So, ToStr creates a z-
string equal to “40,901” and returns the address of it. TV.Str then outputs that string onto the
display. Read the documentation in the Numbers object for more information about this and
other format constants.
TV.Out(13) outputs a single byte, 13, to the display. The 13 is the ASCII code for a carriage
return (a non-visible character) and causes the TV_Terminal object to move to the next text
line. We do this in preparation for the next string we’ll print afterward.
Figure 3-19:
Object View of
Display Application
Yellow folders
indicate objects in the
“work” folder. Blue
folders indicate
objects in the
“library” folder.
The folder icons in front of each object are different colors to indicate their individual folder
locations. Objects with yellow folders are in the “work” folder while those with blue folders
Figure 3-20:
Object View Hints for
Display Application
Pseudo-Real Numbers
For handling real numbers, there are many possible techniques. One technique is to use
integer math in a way that accommodates your real values as well as the run-time expressions
involved. We call this pseudo-real numbers.
Having 32-bit integers built in to the Propeller provides us with a lot of “elbow room” for
calculations. For example, perhaps we have an equation to multiply and divide values that
have 2-digit fractions, like the following:
A=B*C/D
For our example, let’s use A = 7.6 * 38.75 / 12.5 which evaluates to 23.56.
To solve this at run time, we can adjust all the equation’s values upward by 2 digits to make
them all integers, perform the math and then treat the rightmost 2 digits of the result as being
the fractional portion. Multiplying each value by 100 achieves this. Here’s the algebraic
proof:
A = (B* 100) * (C * 100) / (D * 100)
A = (7.6 * 100) * (38.75 * 100) / (12.5 * 100)
A = 760 * 3875 / 1250
A = 2356
Since we multiplied all the original values by 100, we know that the final value is really
2356 / 100 = 23.56, but for most purposes we can keep it in integer form knowing that the
rightmost two digits are really to the right of the decimal point.
The above solution works as long as each of the original values and each of the intermediate
results never exceed the signed integer boundaries: -2,147,483,648 to 2,147,483,647.
The example presented next includes code that uses both the pseudo-real number technique as
well as floating-point numbers.
{{ RealNumbers.spin}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
OBJ
Term : "TV_Terminal"
F : "FloatMath"
FS : "FloatString"
PUB Math
Term.Start(12)
Figure 3-21:
Status Bar with
Compile Information
After a compile
operation, the status
bar’s panel 5 displays
information about the
source item nearest
the cursor.
This tells us that our iB constant is defined by the CON block to be 760 decimal, or $2F8
hexadecimal.
Try placing the cursor on the B constant. The compile information should now read “CON B
= 7.6 ($40F3_3333) Floating Point” to indicate this is a real number, in floating-point form,
equal to 7.6 decimal ($40F3_3333 hexadecimal) This illustrates that floating-point values are
encoded into 32 bits in a way that makes them incompatible with integer values.
In addition to symbols in CON and DAT blocks, the compile information displays shows the
size, in bytes, of PUB/PRI/DAT blocks when the cursor is within that block. In our case, the
Math method is 196 bytes long. This is a great feature to use when optimizing code for size;
make small changes to code, press F9, check size against that of the previous code, and so on.
DAT: Data blocks define data and Propeller Assembly code (page 208).
Assembly p 339 FRQB p 219 PI p 202 TRUNC p 314
BYTE p 165 INA p 225 PLL1X p 180 VCFG p 317
CNT p 184 INB p 225 PLL2X p 180 VSCL p 320
CTRA p 204 LONG p 236 PLL4X p 180 WORD p 331
CTRB p 204 NEGX p 202 PLL8X p 180 XINPUT p 180
DIRA p 212 Operators* p 249 PLL16X p 180 XTAL1 p 180
DIRB p 212 OUTA p 280 POSX p 202 XTAL2 p 180
FALSE p 202 OUTB p 280 RCFAST p 180 XTAL3 p 180
FILE p 215 PAR p 283 RCSLOW p 180
FLOAT p 216 PHSA p 285 ROUND p 303
FRQA p 219 PHSB p 285 TRUE p 202
* Non-assignment operators only.
Block Designators
CON Declare constant block; p 194.
VAR Declare variable block; p 315.
OBJ Declare object reference block; p 247.
PUB Declare public method block; p 287.
PRI Declare private method block; p 286.
DAT Declare data block; p 208.
Configuration
CHIPVER Propeller chip version number; p 174.
CLKMODE Current clock mode setting; p 179.
_CLKMODE Application-defined clock mode (read-only); p 180.
CLKFREQ Current clock frequency; p 175.
_CLKFREQ Application-defined clock frequency (read-only); p 177.
CLKSETa Set clock mode and clock frequency; p 183.
_XINFREQ Application-defined external clock frequency (read-only); p 337.
_STACK Application-defined stack space to reserve (read-only); p 307.
_FREE Application-defined free space to reserve (read-only); p 218.
RCFAST Constant for _CLKMODE: internal fast oscillator; p 180.
RCSLOW Constant for _CLKMODE: internal slow oscillator; p 180.
XINPUT Constant for _CLKMODE: external clock/osc (XI pin); p 180.
XTAL1 Constant for _CLKMODE: external low-speed crystal; p 180.
XTAL2 Constant for _CLKMODE: external med-speed crystal; p 180.
XTAL3 Constant for _CLKMODE: external high-speed crystal; p 180.
PLL1X Constant for _CLKMODE: external frequency times 1; p 180.
PLL2X Constant for _CLKMODE: external frequency times 2; p 180.
PLL4X Constant for _CLKMODE: external frequency times 4; p 180.
Page 152 · Propeller Manual v1.0
4: Spin Language Reference
PLL8X Constant for _CLKMODE: external frequency times 8; p 180.
PLL16X Constant for _CLKMODE: external frequency times 16; p 180.
Cog Control
COGIDa Current cog’s ID (0-7); p 186.
COGNEW Start the next available cog; p 189.
COGINITa Start, or restart, a cog by ID; p 187.
COGSTOPa Stop a cog by ID; p 193.
REBOOT Reset the Propeller chip; p 292.
Process Control
LOCKNEWa Check out a new lock; p 230.
LOCKRETa Release a lock; p 233.
LOCKCLRa Clear a lock by ID; p 228.
LOCKSETa Set a lock by ID; p 234.
WAITCNTa Wait for System Counter to reach a value; p 322.
WAITPEQa Wait for pin(s) to be equal to value; p 326.
WAITPNEa Wait for pin(s) to be not equal to value; p 328.
WAITVIDa Wait for video sync and deliver next color/pixel group; p 329.
Flow Control
IF Conditionally execute one or more blocks of code; p 220.
...ELSEIF
...ELSEIFNOT
...ELSE
Memory
BYTE Declare byte-sized symbol or access byte of main memory; p 165.
WORD Declare word-sized symbol or access word of main memory; p 331.
LONG Declare long-sized symbol or access long of main memory; p 236.
BYTEFILL Fill bytes of main memory with a value; p 169.
WORDFILL Fill words of main memory with a value; p 335.
LONGFILL Fill longs of main memory with a value; p 240.
BYTEMOVE Copy bytes from one region to another in main memory; p 170.
WORDMOVE Copy words from one region to another in main memory; p 336.
LONGMOVE Copy longs from one region to another in main memory; p 241.
LOOKUP Get value at index (1..N) from a list; p 244.
LOOKUPZ Get value at zero-based index (0..N−1) from a list; p 244.
LOOKDOWN Get index (1..N) of a matching value from a list; p 242.
LOOKDOWNZ Get zero-based index (0..N−1) of a matching value from a list; p 242.
STRSIZE Get size of string in bytes; p 311.
STRCOMP Compare a string of bytes against another string of bytes; p 308.
Registers
DIRAa Direction Register for 32-bit port A; p 212.
DIRBa Direction Register for 32-bit port B (future use); p 212.
INAa Input Register for 32-bit port A (read only); p 225.
INBa Input Register for 32-bit port B (read only) (future use); p 226.
OUTAa Output Register for 32-bit port A; p 280.
OUTBa Output Register for 32-bit port B (future use); p 282.
CNTa 32-bit System Counter Register (read only); p 184.
CTRAa Counter A Control Register; p 204.
CTRBa Counter B Control Register; p 204.
FRQAa Counter A Frequency Register; p 219.
FRQBa Counter B Frequency Register; p 219.
PHSAa Counter A Phase-Locked Loop (PLL) Register; p 285.
PHSBa Counter B Phase-Locked Loop (PLL) Register; p 285.
VCFGa Video Configuration Register; p 317.
VSCLa Video Scale Register; p 320.
PARa Cog Boot Parameter Register (read only); p 283.
SPR Special-Purpose Register array; indirect cog register access; p 305.
Variable
RESULT Default result variable for PUB/PRI methods; p 299.
Unary Operators
+ Positive (+X); unary form of Add; p 256.
- Negate (-X); unary form of Subtract; p 256.
-- Pre-decrement (--X) or post-decrement (X--) and assign; p 257.
++ Pre-increment (++X) or post-increment (X++) and assign; p 257.
^^ Square root; p 261.
|| Absolute Value; p 261.
~ Sign-extend from bit 7 (~X) or post-clear to 0 (X~); p 262.
~~ Sign-extend from bit 15 (~~X) or post-set to -1(X~~); p 263.
? Random number forward (?X) or reverse (X?); p 264.
|< Decode value (modulus of 32; 0-31) into single-high-bit long; p 265.
>| Encode long into magnitude (0 - 32) as high-bit priority; p 266.
! Bitwise: NOT; p 272.
NOT Boolean: NOT (promotes non-0 to -1); p 274.
@ Symbol address; p 278.
@@ Object address plus symbol value; p 279.
Symbol Rules
Symbols are case-insensitive, alphanumeric names either created by the compiler (reserved
word) or by the code developer (user-defined word). They represent values (constants or
variables) to make source code easier to understand and maintain. Symbols must fit the
following rules:
1) Begins with a letter (a – z) or an underscore ‘_’.
2) Contains only letters, numbers, and underscores (a – z, 0 – 9, _ ); no spaces allowed.
3) Must be 32 characters or less.
4) Is unique to the object; not a reserved word (p. 419) or previously user-defined symbol.
Value Representations
Values can be entered in binary (base-2), quaternary (base-4), decimal (base-10),
hexadecimal (base-16), or character formats. Numerical values can also use underscores, ‘_’,
as a group separator to clarify numbers. The following are examples of these formats.
Table 4-1: Value Representations
Base Type of Value Examples
2 Binary %1010 –or– %11110000_10101100
4 Quaternary %%2130_3311 –or– %%3311_2301_1012
10 Decimal (integer) 1024 –or– 2_147_483_647 –or– -25
10 Decimal (floating-point) 1e6 –or– 1.000_005 –or– -0.70712
16 Hexadecimal $1AF –or– $FFAF_126D_8755
n/a Character "A"
Separators can be used in place of commas (in decimal values) or to form logical groups,
such as nibbles, bytes, words, etc.
((PUB ┆ PRI))
BYTEFILL (StartAddress, Value, Count )
ABORT
Exit from PUB/PRI method using abort status with optional return Value.
((PUB ┆ PRI))
ABORT 〈Value〉
Returns: Either the current RESULT value, or Value if provided.
• Value is an optional expression whose value is to be returned, with abort status, from
the PUB or PRI method.
Explanation
ABORT is one of two commands (ABORT and RETURN) that terminate a PUB or PRI method’s
execution.
ABORT causes a return from a PUB or PRI method with abort status; meaning it pops the call
stack repeatedly until either the call stack is empty or it reaches a caller with an Abort Trap,
( \ ), and delivers a value in the process.
ABORT is useful for cases where a method needs to terminate and indicate an abnormal or
elevated status to the immediate caller or one its previous callers. For example, an
application may be involved in a complicated chain of events where any one of those events
could lead to a different branch of the chain or a final action decision. It may be easier to
write that application using small, specialized methods that are called in a nested fashion,
each meant to deal with a specific sub-event in the chain. When one of the simple methods
determines a course of action, it can issue an abort that completely collapses the nested call
chain and prevents all the intermediate methods from continuing.
When ABORT appears without the optional Value, it returns the current value of the PUB/PRI’s
built-in RESULT variable. If the Value field was entered, however, the PUB or PRI aborts and
returns that Value instead.
Using ABORT
Any method can choose to issue an ABORT command. It’s up to the higher-level code to
check for an abort status and handle it. This higher-level code can be either that which called
an aborting method directly, or via some other set of methods. To issue an ABORT command,
use something like the following:
if <bad condition>
abort 'If bad condition detected, abort
—or—
if <bad condition>
abort <value> 'If bad condition detected, abort with value
...where <bad condition> is a condition that determines the method should abort and <value>
is a value to return upon aborting.
PUB Move(Direction)
result := TRUE 'Assume success
if Direction == None
return 'Return if no direction
repeat 1000
DriveMotors(Direction) 'Drive motor 1000 times
PUB DriveMotors(Direction)
<code to drive motors>
if MotorStuck
abort FALSE 'If motor is stuck, abort
Propeller Manual v1.0 · Page 163
ABORT – Spin Language Reference
<more code>
The above example shows three methods of various logical levels, Main (“high-level”), Move
(“mid-level”) and DriveMotors (“low-level”). The high-level method, Main, is the decision
maker of the application; deciding how to respond to events like sensor activations and motor
movements. The mid-level method, Move, is responsible for moving the robot a short
distance. The low-level method, DriveMotors, handles the details of driving the motors
properly and verifying that it is successful.
In an application like this, critical events could occur in low-level code that needs to be
addressed by high-level code. The ABORT command can be instrumental in getting the
message to the high-level code without requiring complicated message-passing code for all
the mid-level code in-between. In this case, we have only one mid-level method but there
could be many nested mid-level methods between the high-level and the low-level.
The Main method gets sensor inputs and decides what direction to move the robot via the CASE
statement. It then calls Move in a special way, with the Abort Trap symbol, \ , preceding it.
The Move method sets its RESULT to TRUE and then calls DriveMotors in a finite loop. If it
successfully completes, Move returns TRUE. The DriveMotors method handles the
complication of moving the robot’s motors to achieve the desired direction, but if it
determines the motors are stuck, it cannot move them further and it aborts with a FALSE value.
Otherwise it simply returns normally.
If everything is fine, the DriveMotors method returns normally, the Move method carries on
normally and eventually returns TRUE, and the Main method continues on normally. If,
however, DriveMotors finds a problem, it ABORTs which causes the Propeller to pop the call
stack all the way through the Move method and up to the Main method where the Abort Trap
was found. The Move method is completely oblivious to this and is now effectively
terminated. The Main method checks the value returned by its call to Move (which is now the
FALSE value that was actually returned by the aborted DriveMotors method deep down the call
stack) and it decides to Beep as a result of the detected failure.
If we had not put the Abort Trap, ( \ ), in front of the call to Move, when DriveMotors aborted,
the call stack would have been popped until it was empty and this application would have
terminated immediately.
BYTE
Declare byte-sized symbol, byte aligned/sized data, or read/write a byte of main memory.
VAR
BYTE Symbol 〈[Count]〉
DAT
BYTE Data
((PUB ┆ PRI))
BYTE [BaseAddress] 〈[Offset]〉
((PUB ┆ PRI))
Symbol.BYTE 〈[Offset]〉
• Symbol is the desired name for the variable (Syntax 1) or the existing name of the
variable (Syntax 4).
• Count is an optional expression indicating the number of byte-sized elements for
Symbol, arranged in an array from element 0 to element Count-1.
• Data is a constant expression or comma-separated list of constant expressions.
Quoted strings of characters are also allowed; they are treated as a comma-separated
list of characters.
• BaseAddress is an expression describing the address of main memory to read or write.
If Offset is omitted, BaseAddress is the actual address to operate on. If Offset is
specified, BaseAddress + Offset is the actual address to operate on.
• Offset is an optional expression indicating the offset from BaseAddress to operate on,
or the offset from byte 0 of Symbol.
Explanation
BYTE is one of three multi-purpose declarations (BYTE, WORD, and LONG) that declare or operate
on memory. BYTE can be used to:
1) declare a byte-sized (8-bit) symbol or a multi-byte symbolic array in a VAR block, or
2) declare byte-aligned, and possibly byte-sized, data in a DAT block, or
3) read or write a byte of main memory at a base address with an optional offset, or
4) access a byte within a word-sized or long-sized variable.
The above example declares two variables (symbols), Temp and Str. Temp is simply a single,
byte-sized variable. The line under the Temp declaration uses the optional Count field to
create an array of 25 byte-sized variable elements called Str. Both Temp and Str can be
accessed from any PUB or PRI method within the same object that this VAR block was declared;
they are global to the object. An example of this is below.
PUB SomeMethod
Temp := 250 'Set Temp to 250
Str[0] := "A" 'Set first element of Str to "A"
Str[1] := "B" 'Set second element of Str to "B"
Str[24] := "C" 'Set last element of Str to "C"
For more information about using BYTE in this way, refer to the VAR section’s Variable
Declarations (Syntax 1) on page 315, and keep in mind that BYTE is used for the Size field in
that description.
The above example declares two data symbols, MyData and MyString. Each data symbol
points to the start of byte-aligned and byte-sized data in main memory. MyData’s values, in
main memory, are 64, $AA and 55, respectively. MyString’s values, in main memory, are
“H”, “e”, “l”, “l”, “o”, and 0, respectively. This data is compiled into the object and resulting
application as part of the executable code section and may be accessed using the read/write
Page 166 · Propeller Manual v1.0
4: Spin Language Reference – BYTE
form, syntax 3, of BYTE (see below). For more information about using BYTE in this way, refer
to the DAT section’s Declaring Data (Syntax 1) on page 208, and keep in mind that BYTE is
used for the Size field in that description.
Index := 0
repeat
Temp := MyString[Index++] 'Read chars into Temp
<do something with Temp> 'Perform task with character
while Temp > 0 'Loop until end found
The first line inside of the GetData method, Temp := MyData, reads the first value in the
MyData list (the byte-sized value 64) and stores it in Temp. Further down, in the REPEAT loop,
the Temp := MyString[Index++] line reads a byte of from the location of MyString + Index.
Since Index is earlier set to 0, the first byte of MyString is read, “H”. On that same line Index
is post incremented with ++, so the next time through the loop it reads the next byte,
effectively MyString + 1 (the “e”), and the next time MyString + 2 (the “l”), etc.
Similar to the above, we can use the BYTE declaration to achieve our goal, as in the following
example.
PUB GetData | Index, Temp
Temp := BYTE[@MyData] 'Read 1st byte of MyData to Temp
<do something with Temp> 'Perform task with Temp
Index := 0
repeat
Temp := BYTE[@MyString][Index++] 'Read chars into Temp
<do something with Temp> 'Perform task with character
while Temp > 0 'Loop until end found
This line writes the character “M” to the first byte of string data at MyString, changing the
string to be “Mello”,0.
PUB Main
WordVar.byte := 0 'Set first byte of WordVar to 0
WordVar.byte[0] := 0 'Same as above
WordVar.byte[1] := 100 'Set second byte of WordVar to 100
LongVar.byte := 25 'Set first byte of LongVar to 25
LongVar.byte[0] := 25 'Same as above
LongVar.byte[1] := 50 'Set second byte of LongVar to 50
LongVar.byte[2] := 75 'Set third byte of LongVar to 75
LongVar.byte[3] := 100 'Set fourth byte of LongVar to 100
This example accesses the byte-sized components of both WordVar and LongVar, individually.
The comments indicate what each line is doing. At the end of the Main method, WordVar will
equal 25,600 and LongVar will equal 1,682,649,625.
BYTEFILL
Fill bytes of main memory with a value.
((PUB ┆ PRI))
BYTEFILL (StartAddress, Value, Count )
• StartAddress is an expression indicating the location of the first byte of memory to fill
with Value.
• Value is an expression indicating the value to fill bytes with.
• Count is an expression indicating the number of bytes to fill, starting with
StartAddress.
Explanation
BYTEFILL is one of three commands (BYTEFILL, WORDFILL, and LONGFILL) used to fill blocks of
main memory with a specific value. BYTEFILL fills Count bytes of main memory with Value,
starting at location StartAddress.
Using BYTEFILL
BYTEFILL is a great way to clear large blocks of byte-sized memory. For example:
VAR
byte Buff[100]
PUB Main
bytefill(@Buff, 0, 100) 'Clear Buff to 0
The first line of the Main method, above, clears the entire 100-byte Buff array to all zeros.
BYTEFILL is faster at this task than a dedicated REPEAT loop is.
((PUB ┆ PRI))
BYTEMOVE (DestAddress, SrcAddress, Count )
• DestAddress is an expression specifying the main memory location to copy the first
byte of source to.
• SrcAddress is an expression specifying the main memory location of the first byte of
source to copy.
• Count is an expression indicating the number of bytes of the source to copy to the
destination.
Explanation
BYTEMOVE is one of three commands (BYTEMOVE, WORDMOVE, and LONGMOVE) used to copy blocks
of main memory from one area to another. BYTEMOVE copies Count bytes of main memory
starting from SrcAddress to main memory starting at DestAddress.
Using BYTEMOVE
BYTEMOVE is a great way to copy large blocks of byte-sized memory. For example:
VAR
byte Buff1[100]
byte Buff2[100]
PUB Main
bytemove(@Buff2, @Buff1, 100) 'Copy Buff1 to Buff2
The first line of the Main method, above, copies the entire 100-byte Buff1 array to the Buff2
array. BYTEMOVE is faster at this task than a dedicated REPEAT loop.
CASE
Compare expression against matching expression(s) and execute code block if match found.
((PUB ┆ PRI))
CASE CaseExpression
MatchExpression :
Statement(s)
〈 MatchExpression :
Statement(s) 〉
〈 OTHER :
Statement(s) 〉
Explanation
CASE is one of the three conditional commands (IF, IFNOT, and CASE) that conditionally
executes a block of code. CASE is the preferred structure to use, as opposed to
IF..ELSEIF..ELSE, when you need to compare the equality of CaseExpression to a number of
different values.
CASE compares CaseExpression against the values of each MatchExpression, in order, and if a
match is found, executes the associated Statement(s). If no previous matches were found, the
Statement(s) associated with the optional OTHER command are executed.
Indention is Critical
IMPORTANT: Indention is critical. The Spin language relies on indention (of one space or
more) on lines following conditional commands to determine if they belong to that command
or not. To have the Propeller Tool indicate these logically grouped blocks of code on-screen,
Using CASE
CASE is handy where one of many actions needs to be performed depending on the value of an
expression. The following example assumes A, X and Y are variables defined earlier.
case X+Y 'Test X+Y
10, 15: !outa[0] 'X+Y = 10 or 15? Toggle P0
A*2 : !outa[1] 'X+Y = A*2? Toggle P1
30..40: !outa[2] 'X+Y in 30 to 40? Toggle P2
X += 5 'Add 5 to X
Since the MatchExpression lines are indented from the CASE line, they belong to the CASE
structure and are executed based on the CaseExpression comparison results. The next line,
X += 5, is not indented from CASE, so it is executed regardless of the CASE results.
This example compares the value of X + Y against 10 or 15, A*2 and the range 30 through
40. If X + Y equals 10 or 15, P0 is toggled. If X + Y equals A*2, P1 is toggled. If X + Y is in
the range 30 through 40, inclusive, then P2 is toggled. Whether or not any match was found,
the X += 5 line is executed next.
Using OTHER
The optional OTHER component of CASE is similar to the optional ELSE component of an IF
structure. For example:
case X+Y 'Test X+Y
10, 15: !outa[0] 'X+Y = 10 or 15? Toggle P0
25 : !outa[1] 'X+Y = 25? Toggle P1
20..30: !outa[2] 'X+Y in 20 to 30? Toggle P2
OTHER : !outa[3] 'Othewise toggle P3
X += 5 'Add 5 to X
This example is similar to the last one except that the third MatchStatement checks for the
range 20 to 30 and there’s an OTHER component. If X + Y does not equal 10, 15, 25, or is not
in the range 20 to 30, the Statement(s) block following OTHER is executed. Following that, the
X += 5 line is executed.
There is an important concept to note about this example. If X + Y is 10 or 15, P0 is toggled,
or if X + Y is 25, P1 is toggled, or if X + Y is 20 to 30, P2 is toggled, etc. This is because the
MatchExpressions are checked, one at a time, in the order they are listed and only the first
Page 172 · Propeller Manual v1.0
4: Spin Language Reference – CASE
expression that is a match has its block of code executed; no further expressions are tested
after that. This means that if we had rearranged the 25 and 20..30 lines, so that the range of
20..30 is checked first, we’d have a bug in our code. We did this below:
case X+Y 'Test X+Y
10, 15: !outa[0] 'X+Y = 10 or 15? Toggle P0
20..30: !outa[2] 'X+Y in 20 to 30? Toggle P2
25 : !outa[1] 'X+Y = 25? Toggle P1 <-- THIS NEVER RUNS
The above example contains an error because, while X + Y could be equal to 25, that match
expression would never be tested since the previous one, 20..30 would be tested first, and
since it is true, its block is executed and no further match expressions are checked.
Variations of Statement(s)
The above examples only use one line per Statement(s) block, but each block can be many
lines of course. Additionally, the Statement(s) block may also appear below, and slightly
indented from, the MatchExpression itself. The following two examples show these
variations.
case A 'Test A
4 : !outa[0] 'A = 4? Toggle P0
Z+1 : !outa[1] 'A = Z+1? Toggle P1
!outa[2] 'And toggle P2
10..15: !outa[3] 'A in 10 to 15? Toggle P3
case A 'Test A
4: 'A = 4?
!outa[0] 'Toggle P0
Z+1: 'A = Z+1?
!outa[1] 'Toggle P1
!outa[2] 'And toggle P2
10..15: 'A in 10 to 15?
!outa[3] 'Toggle P3
((PUB ┆ PRI))
CHIPVER
Returns: Version number of the Propeller chip.
Explanation
The CHIPVER command reads and returns the version number of the Propeller chip. For
example:
V := chipver
This example sets V to the version number of the Propeller chip, 1 in this case. Future
Propeller Applications can use this to determine the version and type of Propeller chip they
are running on and make modifications to their operation as necessary.
CLKFREQ
Current System Clock frequency; the frequency at which each cog is running.
((PUB ┆ PRI))
CLKFREQ
Returns: Current System Clock frequency, in Hz.
Explanation
The value returned by CLKFREQ is the actual System Clock frequency as determined by the
current clock mode (oscillator type, gain, and PLL settings) and the external XI pin
frequency, if any. Objects use CLKFREQ to determine the proper time delays for time-sensitive
operations. For example:
waitcnt(clkfreq / 10 + cnt) 'wait for .1 seconds (100 ms)
This statement divides CLKFREQ by 10 and adds the result to CNT (the current System Counter
value) then waits (WAITCNT) until the System Counter reaches the result value. Since CLKFREQ
is the number of cycles per second, a divide by 10 yields the number of clock cycles per 0.1
seconds, or 100 ms. So, disregarding the time it takes to process the expression, this
statement pauses the cog’s program execution for 100 ms. The table below shows more
examples of System Clock tick verses Time calculations.
Table 4-2: System Clock Ticks vs. Time Calculations
Expression Result
clkfreq / 10 Clock ticks per 0.1 seconds (100 ms)
clkfreq / 100 Clock ticks per 0.01 seconds (10 ms)
clkfreq / 1_000 Clock ticks per 0.001 seconds (1 ms)
clkfreq / 10_000 Clock ticks per 0.0001 seconds (100 µs)
clkfreq / 100_000 Clock ticks per 0.00001 seconds (10 µs)
clkfreq / 9600 Clock ticks per serial bit period at 9,600 baud (~ 104 µs)
clkfreq / 19200 Clock ticks per serial bit period at 19,200 baud (~ 52 µs)
The value that CLKFREQ returns can change whenever the application changes the clock mode,
either manually or via the CLKSET command. Objects that are time-sensitive should check
CLKFREQ at strategic points in order to adjust to new settings automatically.
_CLKFREQ
Pre-defined, one-time settable constant for specifying the System Clock frequency.
CON
_CLKFREQ = Expression
• Expression is an integer expression that indicates the System Clock frequency upon
application start-up.
Explanation
_CLKFREQ specifies the System Clock frequency for start-up. It is a pre-defined constant
symbol whose value is determined by the top object file of an application. _CLKFREQ is either
set directly by the application itself, or is set indirectly as the result of the _CLKMODE and
_XINFREQ settings.
The top object file in an application (the one where compilation starts from) can specify a
setting for _CLKFREQ in its CON block. This defines the initial System Clock frequency for the
application and is the frequency that the System Clock will switch to as soon as the
application is booted up and execution begins.
The application can specify either _CLKFREQ or _XINFREQ in the CON block; they are mutually
exclusive and the non-specified one is automatically calculated and set as a result of
specifying the other.
The following examples assume that they are contained within the top object file. Any
_CLKFREQ settings in child objects are simply ignored by the compiler.
For example:
CON
_CLKMODE = XTAL1 + PLL8X
_CLKFREQ = 32_000_000
The first declaration in the above CON block sets the clock mode for an external low-speed
crystal and a Clock PLL multiplier of 8. The second declaration sets the System Clock
frequency to 32 MHz, which means the external crystal’s frequency must be 4 MHz because
4 MHz * 8 = 32 MHz. The _XINFREQ value is automatically set to 4 MHz because of these
declarations.
These two declarations set the clock mode for an external medium-speed crystal, no Clock
PLL multiplier, and a System Clock frequency of 10 MHz. The _XINFREQ value is
automatically set to 10 MHz, as well, because of these declarations.
_CLKFREQ vs CLKFREQ
_CLKFREQ is related to, but not the same as, CLKFREQ. _CLKFREQ contains the application’s
System Clock frequency at startup whereas CLKFREQ is a command that returns the current
System Clock frequency. In other words, _CLKFREQ is the original System Clock frequency
and CLKFREQ is the current System Clock frequency; they both may happen to be the same
value but they certainly can be different.
CLKMODE
Current clock mode setting.
((PUB ┆ PRI))
CLKMODE
Returns: Current clock mode.
Explanation
The clock mode setting is the byte-sized value, determined by the application at compile
time, from the CLK register. See CLK Register, page 28, for explanation of the possible
settings. For example:
Mode := clkmode
This statement can be used to set a variable, Mode, to the current clock mode setting. Many
applications maintain a static clock mode setting; however, some applications will change the
clock mode setting during run time for clock speed adjustments, low-power modes, etc. It
may be necessary for some objects to pay attention to the potential for dynamic clock modes
in order to maintain proper timing and functionality.
CLKMODE vs _CLKMODE
CLKMODE is related to, but not the same as, _CLKMODE. CLKMODE is a command that returns the
current clock mode (in the form of the CLK register’s bit pattern) whereas _CLKMODE is an
application-defined constant containing the requested clock mode at startup (in the form of
clock setting constants that are OR’d together). Both may describe the same logical clock
mode but their values are not equivalent.
CON
_CLKMODE = Expression
Explanation
_CLKMODE is used to specify the desired nature of the System Clock. It is a pre-defined
constant symbol whose value is determined by the top object file of an application. The clock
mode setting is a byte whose value is described by a combination of the RCxxxx, XINPUT,
XTALx and PLLxx constants at compile time. Table 4-3 illustrates the clock mode setting
constants. Note that not every combination is valid; Table 4-4 shows all valid combinations.
The top object file in an application (the one where compilation starts from) can specify a
setting for _CLKMODE in its CON block. This defines the initial clock mode setting for the
application and is the mode that the System Clock will switch to as soon as the application is
booted up and execution begins. The following examples assume that they are contained
within the top object file. Any _CLKMODE settings in child objects are simply ignored by the
compiler. For example:
CON
_CLKMODE = RCFAST
This sets the clock mode for the internal, fast RC Clock/Oscillator circuit. The System Clock
would run at approximately 12 MHz with this setting. The RCFAST setting is the default
setting, so if no _CLKMODE was actually defined, this is the setting that would be used. Note
that the Clock PLL can not be used with the internal RC Clock/Oscillator. Here’s an example
with an external clock:
CON
_CLKMODE = XTAL1 + PLL8X
This sets the clock mode for an external low-speed crystal (XTAL1), enables the Clock PLL
circuit and sets the System Clock to use the 8x tap from the Clock PLL (PLL8X). If an
external 4 MHz crystal was attached to XI and XO, for example, its signal would be
Propeller Manual v1.0 · Page 181
_CLKMODE – Spin Language Reference
multiplied by 16 (the Clock PLL always multiplies by 16) but the 8x result would be used;
the System Clock would be 4 MHz * 8 = 32 MHz.
CON
_CLKMODE = XINPUT + PLL2X
This sets the clock mode for an external clock-oscillator, connected to XI only, and enables
the Clock PLL circuit and sets the System Clock to use the 2x result. If an external clock-
oscillator pack of 8 MHz was attached to XI, the System clock would run at 16 MHz; that’s 8
MHz * 2.
Note that the Clock PLL is not required and can be disabled by simply not specifying any
multiplier setting, for example:
CON
_CLKMODE = XTAL1
This sets the clock mode for an external low-speed crystal but leaves the Clock PLL disabled;
the System Clock will be equal to the external crystal’s frequency.
This example is exactly like the second example above, but _XINFREQ indicates that the
frequency of the external crystal is 4 MHz. The Propeller chip uses this value along with the
_CLKMODE setting to determine the System Clock frequency (as reported by the CLKFREQ
command) so that objects can properly adjust their timing. See _XINFREQ, page 337.
_CLKMODE vs CLKMODE
_CLKMODE is related to, but not the same as, CLKMODE. _CLKMODE is an application-defined
constant containing the requested clock mode at startup (in the form of clock setting constants
that are OR’d together) whereas CLKMODE is a command that returns the current clock mode
(in the form of the CLK register’s bit pattern). Both may describe the same logical clock
mode but their values are not equivalent.
Page 182 · Propeller Manual v1.0
4: Spin Language Reference – CLKSET
CLKSET
Set both the clock mode and System Clock frequency at run time.
((PUB ┆ PRI))
CLKSET (Mode, Frequency)
• Mode is an integer expression that will be written to the CLK register to change the
clock mode.
• Frequency is an integer expression that indicates the resulting System Clock
frequency.
Explanation
One of the most powerful features of the Propeller chip is the ability to change the clock
behavior at run time. An application can choose to toggle back and forth between a slow
clock speed (for low-power consumption) and a fast clock speed (for high-bandwidth
operations), for example. CLKSET is used to change the clock mode and frequency during run
time. It is the run-time equivalent of the _CLKMODE and _CLKFREQ constants defined by the
application at compile time. For example:
clkset(%01101100, 4_000_000) 'Set to XTAL1 + PLL2x
This sets the clock mode to a low-speed external crystal and a Clock PLL multiplier of 2, and
indicates the resulting System Clock frequency (CLKFREQ) is 4 MHz. After executing this
command, the CLKMODE and CLKFREQ commands will report the updated settings for objects
that use them.
When switching from the internal clock to an external crystal, it is important to perform it as
a three-stage process:
1) First set the PLLENA, OSCENA, OSCM1 and OSCM2 bits as necessary,
2) Wait for 10 ms to give the crystal time to stabilize,
3) Set the CLKSELx bits as necessary to switch the System Clock to the new source.
It takes approximately 75 µs for the Propeller Chip to perform the clock source switching
action.
((PUB ┆ PRI))
CNT
Returns: Current 32-bit System Counter value.
Explanation
The CNT register contains the current value in the global 32-bit System Counter. The System
Counter serves as the central time reference for all cogs; it increments its 32-bit value once
every System Clock cycle.
Upon power-up/reset, the System Counter starts with an arbitrary value and counts upwards
from there, incrementing with every System Clock cycle. Since the System Counter is a
read-only resource, every cog can read it simultaneously and can use the returned value to
synchronize events, count cycles and measure time.
Using CNT
Read CNT to get the current System Counter value. The actual value itself does not matter for
any particular purpose, but the difference in successive reads is very important. Most often,
the CNT register is used to delay execution for a specific period or to synchronize an event to
the start of a window of time. The next examples use the WAITCNT instruction to achieve this.
waitcnt(3_000_000 + cnt) 'Wait for 3 million clock cycles
The above code is an example of a “fixed delay.” It delays the cog’s execution for 3 million
system clock cycles (about ¼ second when running with the internal fast oscillator).
The next is an example of a “synchronized delay.” It notes the current count at one place and
performs an action (toggles a pin) every millisecond thereafter with accuracy as good as that
of the oscillator driving the Propeller chip.
PUB Toggle | TimeBase, OneMS
dira[0]~~ 'Set P0 to output
OneMS := clkfreq / 1000 'Calculate cycles per 1 millisecond
TimeBase := cnt 'Get current count
repeat 'Loop endlessly
waitcnt(TimeBase += OneMS) ' Wait to start of next millisecond
!outa[0] ' Toggle P0
Page 184 · Propeller Manual v1.0
4: Spin Language Reference – CNT
Here, I/O pin 0 is set to output. Then the local variable OneMS is set equal to the current
System Clock frequency divided by 1000; i.e.: the number of System Clock cycles per 1
millisecond of time. Next, the local variable TimeBase is set to the current System Counter
value. Finally, the last two lines of code repeat endlessly; each time waiting until the start of
the next millisecond and then toggling the state of P0.
For more information, see the WAITCNT sections’s Fixed Delays on page 322 and
Synchronized Delays on page 323.
((PUB ┆ PRI))
COGID
Returns: The current cog’s ID (0-7).
Explanation
The value returned by COGID is the ID of the cog that executed the command. Normally, the
actual cog that code is running in does not matter, however, for some objects it might be
important to keep track of it. For example:
PUB StopMyself
'Stop cog this code is running in
cogstop(cogid)
This example method, StopMyself, has one line of code that simply calls COGSTOP with COGID
as the parameter. Since COGID returns the ID of the cog running that code, this routine causes
the cog to terminate itself.
COGINIT
Start or restart a cog by ID to run the Spin code or Propeller Assembly code.
((PUB ┆ PRI))
COGINIT (CogID, SpinMethod 〈(ParameterList)〉, StackPointer )
((PUB ┆ PRI))
COGINIT (CogID, AsmAddress, Parameter )
• CogID is the ID (0 – 7) of the cog to start, or restart. A CogID above 7 results in the
next available cog being started (if possible).
• SpinMethod is the PUB or PRI Spin method that the affected cog should run.
Optionally, it can be followed by a parameter list enclosed in parentheses.
• ParameterList is an optional, comma-delimited list of one or more parameters for
SpinMethod. It must be included only if SpinMethod requires parameters.
• StackPointer is a pointer to memory, such as a long array, reserved for stack space for
the affected cog. The affected cog uses this space to store temporary data during
further calls and expression evaluations. If insufficient space is allocated, either the
application will fail to run or it will run with strange results.
• AsmAddress is the address of a Propeller Assembly routine from a DAT block.
• Parameter is used to optionally pass a value to the new cog. This value ends up in the
affected cog’s read-only Cog Boot Parameter (PAR) register. Parameter can be used
to pass a either a single 14-bit value or the address of a block of memory to be used
by the assembly routine. Parameter is required by COGINIT, but if not needed for
your routine simply set it to an innocuous value like zero (0).
Explanation
COGINIT works exactly like COGNEW with two exceptions: 1) it launches code into a specific
cog whose ID is CogID, and 2) it does not return a value. Since COGINIT operates on a
specific cog, as directed by the CogID parameter, it can be used to stop and restart an active
cog in one step. This includes the current cog; i.e.: a cog can use COGINIT to stop and restart
itself to run, perhaps, completely different code.
This example launches the Propeller Assembly routine, Update, into Cog 2 with the address
of Pos in Cog 2’s PAR parameter. See COGNEW, page 189, for more information.
COGNEW
Start the next available cog to run Spin code or Propeller Assembly code.
((PUB ┆ PRI))
COGNEW (SpinMethod 〈(ParameterList)〉, StackPointer )
((PUB ┆ PRI))
COGNEW (AsmAddress, Parameter )
Returns: The ID of the newly started cog (0-7) if successful, or -1 otherwise.
• SpinMethod is the PUB or PRI Spin method that the new cog should run. Optionally, it
can be followed by a parameter list enclosed in parentheses.
• ParameterList is an optional, comma-delimited list of one or more parameters for
SpinMethod. It must be included only if SpinMethod requires parameters.
• StackPointer is a pointer to memory, such as a long array, reserved for stack space for
the new cog. The new cog uses this space to store temporary data during further calls
and expression evaluations. If insufficient space is allocated, either the application
will fail to run or it will run with strange results.
• AsmAddress is the address of a Propeller Assembly routine, usually from a DAT block.
• Parameter is used to optionally pass a value to the new cog. This value ends up in the
new cog’s read-only Cog Boot Parameter (PAR) register. Parameter can be used to
pass a either a single 14-bit value or the address of a block of memory to be used by
the assembly routine. Parameter is required by COGNEW, but if not needed for your
routine, simply set it to an innocuous value like zero (0).
Explanation
COGNEW starts a new cog and runs either a Spin method or a Propeller Assembly routine within
it. If successful, COGNEW returns the ID of the newly started cog. If there were no more cogs
available, COGNEW returns -1.
PUB Main | X
X := 2 'Initialize X
cognew(Square(@X), @SqStack) 'Launch square cog
<check X here> 'Loop here and check X
PUB Square(XAddr)
'Square the value at XAddr
repeat 'Repeat the following endlessly
long[XAddr] *= long[XAddr] ' Square value, store back
waitcnt(2_000_000 + cnt) ' Wait 2 million cycles
This example shows two methods, Main and Square. Main starts another cog that runs Square
endlessly, then Main can monitor the results in the X variable. Square, being run by another
cog, takes the value of XAddr, squares it and stores the result back into XAddr, then waits for 2
million cycles before it does it again. More explanation follows, but the result is that X starts
out as 2, and the second cog, running Square, iteratively sets X to 4, 16, 256, 65536 and then
finally to 0 (it overflowed 32 bits), all independent of the first cog which may be checking the
value of X or performing some other task.
The Main method declares a local variable, X, that is set to 2 in its first line. Then Main starts a
new cog, with COGNEW, to run the Square method in a separate cog. COGNEW’s first parameter,
Square(@X), is the Spin method to run and its required parameter; in this case we pass it the
address of the X variable. The second parameter of COGNEW, @SqStack, is the address of stack
space reserved for the new cog. When a cog is started to run Spin code, it needs some stack
space where it can store temporary data such as call stacks, parameters and intermediate
expression results. This example only requires 6 longs of stack space for proper operation
(see the “Stack Length” object in the Propeller Library for more information).
After the COGNEW command is executed, two cogs are running; the first is still running the Main
method and the second is starting to run the Square method. Despite the fact that they are
PUB Stop
'Stop the cog we started earlier, if any.
if Cog
cogstop(Cog~ - 1)
This example shows two methods, Start and Stop, within a hypothetical object. The design
of that object is such that it needs to launch another cog to run an assembly routine, called
Update (not shown), and pass it a parameter, Pos. Later it may need to stop that new cog.
The Start method takes a single parameter, Pos, and returns TRUE or FALSE to indicate
whether or not a new cog was successfully started. First, it calls COGNEW, “cognew(@Update,
Pos)” with the address of the Update routine as the first parameter and Pos as the second
parameter. Additionally, it takes the value returned by COGNEW, which is the ID of the new
cog, or -1 if none available, adds 1 and stores the result in the Cog variable; “Cog :=
cognew(@Update, Pos) + 1”. Lastly, if Cog is greater than zero (0) it sets its return value,
Pass, to TRUE; otherwise Pass is set to FALSE. At this point, if a new cog was successfully
started, that new cog begins loading up the Propeller Assembly code called Update, and runs
it. Meanwhile this object’s Cog variable (in the original cog) will be in the range 1 to 8,
representing the new cog’s ID, 0 through 7. If no cog was started, Cog will be 0.
It’s important to note that the Parameter field is intended to pass a long address, so only 14-
bits (bits 2 through 15) are passed into the cog’s PAR register.
COGSTOP
Stop cog by its ID.
((PUB ┆ PRI))
COGSTOP (CogID )
Explanation
COGSTOP stops a cog whose ID is CogID and places that cog into a dormant state. In the
dormant state, the cog ceases to receive System Clock pulses so that power consumption is
greatly reduced.
To stop a cog, issue the COGSTOP command with the ID of the cog to stop. For example:
VAR
byte Cog 'Used to store ID of newly started cog
PUB Stop
'Stop the cog we started earlier, if any.
if Cog
cogstop(Cog~ - 1)
This example, from the COGNEW description, uses COGSTOP in the public Stop method to stop
the cog that was previously started by the Start method. See COGNEW, page 189, for more
information about this example.
CON
Symbol = Expression 〈(( ,┆ )) Symbol = Expression〉…
CON
#Expression (( ,┆ )) Symbol 〈(( ,┆ )) Symbol〉…
CON
Symbol 〈(( ,┆ )) Symbol〉…
Explanation
The Constant Block is a section of source code that declares global constant symbols and
global Propeller configuration settings. This is one of six special declarations (CON, VAR, OBJ,
PUB, PRI, and DAT) that provide inherent structure to the Spin language.
Constants are numerical values that can not change during run time. They can be defined in
terms of single values (1, $F, 65000, %1010, %%2310, “A”, etc.) or as expressions, called
constant expressions, (25 + 16 / 2, 1000 * 5, etc.) that always resolve to a specific number.
The Constant Block is an area of code specifically used for assigning symbols (useful names)
to constants so that the symbols can be used anywhere in code where that constant value is
needed. This makes code more readable and easier to maintain should you later have to
change the value of a constant that appears in many places. These constants are global to the
object so that any method within it can use them. There are many ways to define constants,
described below.
—or—
CON
Delay = 500, Baud = 9600, AChar = "A"
Both of these examples create a symbol called Delay that is equal to 500, a symbol called
Baud that is equal to 9600, and a symbol called AChar that is equal to the character “A”. For
the Delay declaration, for example, we could also have used an algebraic expression, such as:
Delay = 250 * 2
The above statement results in Delay equaling 500, like before, but the expression may make
the code easier to understand if the resulting number were not just an arbitrary value.
The CON block is also used for specifying global settings, such as system clock settings. The
example below shows how to set the Clock Mode to low-speed crystal, the Clock PLL to 8x,
and specify that the XIN pin frequency is 4 MHz.
CON
_CLKMODE = XTAL1 + PLL8X
_XINFREQ = 4_000_000
See _CLKMODE, page 180, and _XINFREQ, page 337, for detailed descriptions of these settings.
Floating-point values can also be defined as constants. Floating-point values are real
numbers (with fractional components) and are encoded within 32 bits differently than integer
constants. To specify a floating-point constant, you must give a clear indication that the
value is a floating-point value; the expression must either be a single floating-point value or
be made up entirely of floating-point values (no integers).
Floating-point values must be written as:
1) decimal digits followed by a decimal point and at least one more decimal digit,
2) decimal digits followed by “e” (for exponent) and an integer exponent value, or,
3) a combination of 1 and 2.
The above code sets Num1, Num2 and Num3 to 20, 127.38 and 573.736, respectively. Notice that
the last expression required Num1 to be enclosed in the FLOAT declaration so that the compiler
treats it as a floating-point value.
The Propeller compiler handles floating-point constants as a single-precision real number as
described by the IEEE-754 standard. Single-precision real numbers are stored in 32 bits, with
a 1-bit sign, an 8-bit exponent, and a 23-bit mantissa (the fractional part). This provides
approximately 7.2 significant decimal digits.
For run-time floating-point operations, the FloatMath and FloatString objects provide math
functions compatible with single-precision numbers.
See FLOAT on page 216, ROUND on page 303, TRUNC on page 314, and the FloatMath and
FloatString objects for more information.
The above example would suffice for our purposes; now users of our object can indicate
“RunFull” instead of “3” to specify the desired mode of operation. The problem is, defining a
logical group of items this way may cause bugs and maintenance problems because if any
value was changed (on purpose or by accident) without changing the rest accordingly, it may
cause the program to fail. Also, imagine a case where there were 20 modes of operation.
That would be a much longer set of constants and even more opportunities for maintenance
issues.
Enumerations solve these problems by automatically incrementing values for symbols. We
can rewrite the above example with enumeration syntax as follows:
CON 'Declare modes of operation
#0, RunTest, RunVerbose, RunBrief, RunFull
Here, #0, tells the compiler to start counting from the number 0 and it sets the next symbol
equal to that value. Then, any additional symbols that do not specify their own value (via an
‘= expression’) are automatically assigned the previous value plus 1. The result is that
RunTest equals 0, RunVerbose equals 1, RunBrief equals 2 and RunFull equals 3. For most
cases, the values themselves don’t usually matter; all that matters is that they are each
assigned a unique number. Defining enumerated values like this has the advantages of
insuring that the assigned values are unique and contiguous within the group.
Notice that these routines do not rely on the exact value of the mode, but rather they rely on
the enumerated mode symbol itself for comparisons as well as the position of the symbol in
relation to other symbols in the same enumeration. It is important to write code this way to
decrease potentials for bugs introduced by future changes.
Enumerations don’t have to consist of comma-separated items either. The following also
works and leaves room for right-side comments about each mode.
CON 'Declare modes of operation
#0
RunTest 'Run in test mode
RunVerbose 'Run in verbose mode
RunBrief 'Run with brief prompts
RunFull 'Run in full production mode
The above example does the same thing as the previous in-line example, but now we have
convenient room to describe the purpose of each mode without losing the automatic
incrementing advantage. Later on, if there’s a need to add a fifth mode, simply add it to the
list in whatever position is necessary. If there is a need for the list to begin at a certain value,
simply change the #0 to whatever you need: #1, #20, etc.
It is even possible to modify the enumerated value in the middle of the list.
CON
'Declare modes of operation
#1, RunTest, RunVerbose, #5, RunBrief, RunFull
Scope of Constants
Symbolic constants defined in Constant Blocks are global to the object in which they are
defined but not outside of that object. This means that constants can be accessed directly
from anywhere within the object but their name will not conflict with symbols defined in
other parent or child objects.
Symbolic constants can be indirectly accessed by parent objects, however, by using the
constant reference syntax. Example:
OBJ
Num : "Numbers"
PUB SomeRoutine
Format := Num#DEC 'Set Format to Number's Decimal constant
Here an object, “Numbers,” is declared as the symbol Num. Later, a method refers to numbers’
DEC constant with Num#DEC. Num is the object reference, # indicates we need to access that
object’s constants, and DEC is the constant within the object we need. This feature allows
objects to define constants for use with themselves and for parent objects to access those
constants freely without interfering with any symbols they created themselves.
((PUB ┆ PRI))
CONSTANT (ConstantExpression )
Returns: Resolved value of constant expression.
Explanation
The CON block may be used to create constants from expressions that are referenced from
multiple places in code, but there are occasions when a constant expression is needed for
temporary, one-time purposes. The CONSTANT directive is used to fully resolve a method’s in-
line, constant expression at compile time. Without the use of the CONSTANT directive, a
method’s in-line expressions are always resolved at run time, even if the expression is always
a constant value.
Using CONSTANT
The CONSTANT directive can create one-time-use constant expressions that save code space and
speed up run-time execution. Note the two examples below:
Example 1, using standard run-time expressions:
CON
X = 500
Y = 2500
PUB Blink
!outa[0]
waitcnt(X+200 + cnt) 'Standard run-time expression
!outa[0]
waitcnt((X+Y)/2 + cnt) 'Standard run-time expression
Example 2, same as above, but with CONSTANT directive around constant, run-time
expressions:
PUB Blink
!outa[0]
waitcnt(constant(X+200) + cnt) 'exp w/compile & run-time parts
!outa[0]
waitcnt(constant((X+Y)/2) + cnt)'exp w/compile & run-time parts
The above two examples do exactly the same thing: their Blink methods toggle P0, wait for
X+200 cycles, toggle P0 again and wait for (X+Y)/2 cycles before returning. While the CON
block’s X and Y symbols may need to be used in multiple places within the object, the WAITCNT
expressions used in each example’s Blink method might only need to be used in that one
place. For this reason, it may not make sense to define additional constants in the CON block
for things like X+200 and (X+Y)/2. There is nothing wrong with putting the expressions right
in the run-time code, as in Example 1, but that entire expression is unfortunately evaluated at
run time, requiring extra time and code space.
The CONSTANT directive is perfect for this situation, because it completely resolves each one-
time-use constant expression to a single, static value, saving code space and speeding up
execution. In Example 1, the Blink method consumes 33 bytes of code space while Example
2’s Blink method, with the addition of the CONSTANT directives, only requires 23 bytes of
space. Note that the “+ cnt” portion of the expressions are not included within the CONSTANT
directive’s parentheses; this is because cnt is a variable (the System Counter variable; see
CNT, page 184) so its value cannot be resolved at compile time.
If a constant needs to be used in more than one place in code, it is better to define it in the CON
block so it is defined only once and the symbol representing it can be used multiple times.
Constants (pre-defined)
—or—
PUB FindListItem(Item) : Index
Index := NEGX 'Default to "not found" response
<code to find Item in list>
if <item found>
Index := <items index>
PI
PI can be used for floating-point calculations, either floating-point constants or floating-point
variable values using the FloatMath and FloatString object.
((PUB ┆ PRI))
CTRA
((PUB ┆ PRI))
CTRB
Returns: Current value of Counter A or Counter B Control Register, if used as a source
variable.
Explanation
CTRA and CTRB are two of six registers (CTRA, CTRB, FRQA, FRQB, PHSA, and PHSB) that affect the
behavior of a cog’s Counter Modules. Each cog has two identical counter modules (A and B)
that can perform many repetitive tasks. The CTRA and CTRB registers contain the
configuration settings of the Counter A and Counter B Modules, respectively.
The following discussion uses CTRx, FRQx and PHSx to refer to both the A and B pairs of each
register.
Each of the two counter modules can control or monitor up to two I/O pins and perform
conditional 32-bit accumulation of the value in the FRQx register into the PHSx register on
every clock cycle. Each Counter Module has its own phase-locked loop (PLLx) which can be
used to synthesize frequencies from 64 MHz to 128 MHz.
With just a little configuration and in some cases a little maintenance from the cog, the
counter modules can be used for:
• Frequency synthesis • Pulse-width modulation (PWM)
• Frequency measurement • Duty-cycle measurement
• Pulse counting • Digital-to-analog conversion (DAC)
• Pulse measurement • Analog-to-digital conversion (ADC)
• Multi-pin state measurement • And more.
For some of these operations the cog can set the counter’s configuration, via CTRA or CTRB,
and it will perform its task completely independently. For others, the cog may use WAITCNT to
time-align the counter’s reads and writes within a loop; creating the effect of a more complex
APIN
The APIN field of CTRA selects a primary I/O pin for that counter. May be ignored if not
used. %0xxxxx = Port A, %1xxxxx = Port B (reserved for future use). In Propeller
Assembly, the APIN field can conveniently be written using the MOVS instruction.
Note that writing a zero to CTRA will immediately disable the Counter A and stop all related
pin output and PHSA accumulation.
BPIN
The BPIN field of CTRx selects a secondary I/O pin for that counter. This field may be
ignored if not used. %0xxxxx = Port A, %1xxxxx = Port B (reserved for future use). In
Propeller Assembly, the BPIN field can conveniently be written using the MOVD instruction.
PLLDIV
The PLLDIV field of CTRx selects a PLLx output tap, see table below. This determines which
power-of-two division of the VCO frequency will be used as the final PLLx output (a range
of 500 KHz to 128 MHz). This field may be ignored if not used. In Propeller Assembly, the
PLLDIV field can conveniently be written, along with CTRMODE, using the MOVI
instruction.
The above code sets CTRA’s CTRMODE field to the NCO mode (%00100) and all other bits
to zero.
DAT
〈Symbol〉 Alignment 〈Size〉 〈Data〉 〈, 〈Size〉 Data〉…
DAT
〈Symbol〉 〈Condition〉 Instruction 〈Effect(s)〉
• Symbol is an optional name for the data, reserved space, or instruction that follows.
• Alignment is the desired alignment and default size (BYTE, WORD, or LONG) of the data
elements that follow.
• Size is the desired size (BYTE, WORD, or LONG) of the following data element
immediately following it; alignment is unchanged.
• Data is a constant expression or comma-separated list of constant expressions.
Quoted strings of characters are also allowed; they are treated as a comma-separated
list of characters.
• Condition is an assembly language condition, IF_C, IF_NC, IF_Z, etc.
• Instruction is an assembly language instruction, ADD, SUB, MOV, etc., and all its operands.
• Effect(s) is/are one, two or three assembly language effects that cause the result of the
instruction to be written or not, NR, WR, WC, or WZ.
Explanation
A Data Block is a section of source code that contains pre-defined data, memory reserved for
run-time use and Propeller Assembly code. This is one of six special declarations (CON, VAR,
OBJ, PUB, PRI, and DAT) that provide inherent structure to the Spin language.
Data blocks are multi-purpose sections of source code that are used for data tables, run-time
workspace, and Propeller Assembly code. Assembly code and data can be intermixed, if
necessary, so that data is loaded into a cog along with the assembly code.
The first thing on line two of this example, BYTE, indicates the data following it should be
byte-aligned and byte-sized. At compile time, the data following BYTE, 64, “A”, etc., is stored
in program memory a byte at a time starting at the next available location. Line three
specifies word-aligned and word-sized data. Its data, $FFC2 and 75000, will begin at the next
word boundary position following the data that appeared before it; with any unused bytes
from the previous data filled with zeros to pad up to the next word boundary. The fourth line
specifies long-aligned and long-sized data; its data will be stored at the next long boundary
following the word-aligned data that appeared before it, with zero-padded words leading up
to that boundary. Table 4-8 shows what this looks like in memory (shown in hexadecimal).
The first nine bytes (0 – 8) are the byte data from line one; $40 = 64 (decimal), $41 = “A”,
$53 = “S”, etc. Byte 9 is padded with zero to align the first word of word-aligned data,
$FFC2, at byte 10. Bytes 10 and 11 (word 5) contain the first word-sized value, $FFC2,
stored in low-byte-first format as $C2 and $FF. Bytes 12 and 13 (word 6) is the lowest word
of 75000; more on this later. Bytes 14 and 15 (word 7) are zero padded to align the first long
of long-aligned data, $44332211. Bytes 16 through 19 (long 5) contain that value in low-
byte-first format. Finally, bytes 20 through 23 (long 6) contains the second long of data, 32,
in low-byte-first format.
You may have noticed that the value 75000 was specified as a word-sized one. The number
75000 in hexadecimal is $124F8, but since that’s larger than a word, only the lowest word
($24F8) of the value was stored. This resulted in word 6 (bytes 12 and 13) containing $F8
and $24, and word 7 (bytes 14 and 15) containing $00 and $00 due to the padding for the
following long-aligned values.
...results in only the low bytes of each value, $AA and $11 being stored in consecutive
locations.
Occasionally, however, it is desirable to store an entire large value as smaller elemental units
that are not necessarily aligned according to the size of the value itself. To do this, specify
the value’s size just before the value itself.
DAT
byte word $FFAA, long $BB995511
This example specifies byte-aligned data, but a word-sized value followed by a long-sized
value. The result is that the memory contains $AA and $FF, consecutively, and following it,
$11, $55, $99 and $BB.
If we modify line three of the first example above as follows:
word $FFC2, long 75000
...then we’d end up with $F8, $24, $01, and $00 occupying bytes 12 through 15. Byte 15 is
the upper byte of the value and it just happens to be immediately left of the next long
boundary so no additional zero-padded bytes are needed for the next long-aligned data.
Optionally, the Symbol field of syntax 1 can be included to “name” the data. This makes
referencing the data from a PUB or PRI block easy. For example:
DAT
MyData byte $FF, 25, %1010
This example creates a data table called MyData that consists of bytes $FF, 25 and %1010.
The public method, GetData, reads the first byte of MyData from main memory and stores it in
its local variable, Temp.
You can also use the BYTE, WORD, and LONG declarations to read main memory locations. For
example:
Page 210 · Propeller Manual v1.0
4: Spin Language Reference – DAT
DAT
MyData byte $FF, 25, %1010
This example is similar to the previous one except that it uses the BYTE declaration to read the
value stored at the address of MyData. Refer to BYTE, page 165; WORD, page 331; and LONG,
page 236, for more information on reading and writing main memory.
This example contains optional symbols, “Loop” and “:arg”, an optional conditional, “IF_Z”,
the required instruction field, ORG, RDLONG, etc, followed by operands and an effect statement,
“WZ.”
Note that any dual commands (those available in both Spin and Propeller Assembly) that are
used in a DAT block are treated as assembly instructions. Conversely, any dual commands that
are used outside of a DAT block are treated as Spin commands.
((PUB ┆ PRI))
DIRA 〈[Pin(s)]〉
((PUB ┆ PRI))
DIRB 〈[Pin(s)]〉 (Reserved for future use)
Returns: Current value of direction bits for I/O Pin(s) in Ports A or B, if used as a source
variable.
Explanation
DIRA and DIRB are one of six registers (DIRA, DIRB, INA, INB, OUTA and OUTB) that directly affect
the I/O pins. The DIRA register holds the direction states for each of the 32 I/O pins in Port A;
bits 0 through 31 correspond to P0 through P31. The DIRB register holds the direction states
for each of the 32 I/O pins in Port B; bits 0 through 31 correspond to P32 through P63.
NOTE: DIRB is reserved for future use; the Propeller P8X32A does not include Port B I/O
pins so only DIRA is discussed below.
DIRA is used to both set and get the current direction states of one or more I/O pins in Port A.
A low (0) bit sets the corresponding I/O pin to an input direction. A high (1) bit sets the
corresponding I/O pin to an output direction. The DIRA register defaults zero, all 0 bits, upon
cog startup; all I/O pins are specified as inputs by that cog until the code instructs otherwise.
Each cog has access to all I/O pins at any given time. Essentially, all I/O pins are directly
connected to each cog so that there is no hub-related mutually-exclusive access involved.
Each cog maintains its own DIRA register that gives it the ability to set any I/O pin’s direction.
Each cog’s DIRA register is OR’d with that of the other cogs’ DIRA registers and the resulting
32-bit value becomes the I/O directions of Port A pins P0 through P31. The result is that
each I/O pin’s direction state is the “wired-OR” of the entire cog collective. See I/O Pins on
page 26 for more information.
Using DIRA
Set or clear bits in DIRA to affect the direction of I/O pins as desired. For example:
DIRA := %00000000_00000000_10110000_11110011
The above code sets the entire DIRA register (all 32 bits at once) to a value that makes I/O pins
15, 13, 12, 7, 6, 5, 4, 1 and 0 to outputs and the rest to inputs.
Using the post-clear (~) and post-set (~~) unary operators, the cog can set all I/O pins to
inputs, or outputs, respectively; it’s not usually desirable to set all I/O pins to outputs,
however. For example:
DIRA~ 'Clear DIRA register (all I/Os are inputs)
—and—
DIRA~~ 'Set DIRA register (all I/Os are outputs)
The first example above clears the entire DIRA register (all 32 bits at once) to zero; all I/Os P0
through P31 to inputs. The second example above sets the entire DIRA register (all 32 bits at
once) to ones; all I/Os P0 through P31 to outputs.
To affect only one I/O pin (one bit), include the optional Pin(s) field. This treats the DIRA
register as an array of 32 bits.
DIRA[5]~~ 'Set DIRA bit 5 (P5 to output)
This sets P5 to an output. All other bits of DIRA (and thus all other corresponding I/O pins)
remain in their previous state.
This sets P5, P4 and P3 to outputs; all other bits of DIRA remain in their previous state. Here’s
another example:
DIRA[5..3] := %110 'Set P5 and P4 to output, P3 to input
The above example sets DIRA bits 5, 4 and 3 equal to 1, 1, and 0, respectively, leaving all
other bits in their previous state. Consequently, P5 and P4 are now outputs and P3 is an
input.
IMPORTANT: The order of the values in a range-expression affects how it is used. For
example, the following swaps the order of the range-expression of the previous example.
DIRA[3..5] := %110 'Set P3 and P4 to output, P5 to input
Here, DIRA bits 3, 4 and 5 are set equal to 1, 1, and 0, respectively, making P3 and P4 outputs
and P5 an input.
This is a powerful feature of range-expressions, but if care is not taken, it can also cause
strange, unintentional results.
Normally DIRA is only written to but it can also be read from to retrieve the current I/O pin
directions. The following assumes Temp is a variable created elsewhere:
Temp := DIRA[7..4] 'Get direction of P7 through P4
The above sets Temp equal to DIRA bits 7, 6, 5, and 4; i.e.: the lower 4 bits of Temp are now
equal to DIRA7:4 and the other bits of Temp are cleared to zero.
FILE
Import external file as data.
DAT
FILE "FileName"
• FileName is the name, without extension, of the desired data file. Upon compile, a file
with this name is searched for in the editor tabs, the working directory and the library
directory. FileName can contain any valid filename characters; disallowed characters
are \, /, :, *, ?, ", <, >, and |.
Explanation
The FILE directive is used to import an external data file (usually a binary file) into the DAT
block of an object. The data can then be accessed by the object just like any regular DAT
block data.
Using FILE
FILE is used in DAT blocks similar to how BYTE would be used, except that following it is a
filename in quotes instead of data values. For example:
DAT
Str byte "This is a data string.", 0
Data file "Datafile.dat"
In this example, the DAT block is made up of a byte string followed by the data from a file
called Datafile.dat. Upon compile, the Propeller Tool will search through the editor tabs, the
working directory or the library directory for a file called Datafile.dat and will load its data
into the first byte following the zero-terminated string, Str. Methods can access the imported
data using the BYTE, WORD or LONG declarations as they would normal data. For example:
PUB GetData | Index, Temp
Index := 0
repeat
Temp := byte[Data][Index++] 'Read data into Temp 1 byte at a time
<do something with Temp> 'Perform task with value in Temp
while Temp > 0 'Loop until end found
This example will read the imported data, one byte at a time, until it finds a byte equal to 0.
Explanation
FLOAT is one of three directives (FLOAT, ROUND and TRUNC) used for floating-point constant
expressions. The FLOAT directive converts a constant integer value to a constant floating-
point value.
Using FLOAT
While most constants are 32-bit integer values, the Propeller compiler supports 32-bit
floating-point values and constant expressions for compile-time use. Note that this is for
constant expressions only, not run-time variable expressions.
For typical floating-point constant declarations, the expression must be shown as a floating-
point value in one of three ways: 1) as an integer value followed by a decimal point and at
least one digit, 2) as an integer with an E followed by an exponent value, or 3) both 1 and 2.
For example:
CON
OneHalf = 0.5
Ratio = 2.0 / 5.0
Miles = 10e5
The above code creates three floating-point constants. OneHalf is equal to 0.5, Ratio is equal
to 0.4 and Miles is equal to 1,000,000.
Notice that in the above example, every component of every expression is shown as a
floating-point value. Now take a look at the following example:
CON
Two = 2
Ratio = Two / 5.0
Page 216 · Propeller Manual v1.0
4: Spin Language Reference – FLOAT
Here, Two is defined as an integer constant and Ratio appears to be defined as a floating-point
constant. This causes an error on the Ratio line because, for floating-point constant
expressions, every value within the expression must be a floating-point value; you cannot mix
integer and floating-point values like Ratio = 2 / 5.0.
You can, however, use the FLOAT directive to convert an integer value to a floating-point
value, such as in the following:
CON
Two = 2
Ratio = float(Two) / 5.0
The FLOAT directive in this example converts the integer constant, Two, into the floating-point
form of that value so that it can be used in the floating-point expression.
CON
_FREE = Expression
• Expression is an integer expression that indicates the number of longs to reserve for
free space.
Explanation
_FREE is a pre-defined, one-time settable optional constant that specifies the required free
memory space of an application. This value is added to _STACK, if specified, to determine the
total amount of free/stack memory space to reserve for a Propeller Application. Use _FREE if
an application requires a minimum amount of free memory in order to run properly. If the
resulting compiled application is too large to allow the specified free memory, an error
message will be displayed. For example:
CON
_FREE = 1000
The _FREE declaration in the above CON block indicates that the application needs to have at
least 1,000 longs of free memory left over after compilation. If the resulting compiled
application does not have that much room left over, an error message will indicate by how
much it was exceeded. This is a good way to prevent successful compiles of an application
that will fail to run properly due to lack of memory.
Note that only the top object file can set the value of _FREE. Any child object’s _FREE
declarations will be ignored.
FRQA, FRQB
Counter A and Counter B frequency registers.
((PUB ┆ PRI))
FRQA
((PUB ┆ PRI))
FRQB
Returns: Current value of Counter A or Counter B Frequency Register, if used as a source
variable.
Explanation
FRQA and FRQB are two of six registers (CTRA, CTRB, FRQA, FRQB, PHSA, and PHSB) that affect the
behavior of a cog’s Counter Modules. Each cog has two identical counter modules (A and B)
that can perform many repetitive tasks. The FRQA register contains the value that is
accumulated into the PHSA register. The FRQB register contains the value that is accumulated
into the PHSB register. See CTRA, CTRB on page 204 for more information.
The above code sets FRQA to $00001AFF. Depending on the CTRMODE field of the CTRA
register, this value in FRQA may be added into the PHSA register at a frequency determined by
the System Clock and the primary and/or secondary I/O pins. See CTRA, CTRB on page 204 for
more information.
((PUB ┆ PRI))
IF Condition(s)
IfStatement(s)
〈 ELSEIF Condition(s)
ElseIfStatement(s) 〉…
〈 ELSEIFNOT Condition(s)
ElseIfNotStatement(s) 〉…
〈 ELSE
ElseStatement(s) 〉
Explanation
IF is one of the three major conditional commands (IF, IFNOT, and CASE) that conditionally
executes a block of code. IF can optionally be combined with one or more ELSEIF
commands, one or more ELSEIFNOT commands, and/or an ELSE command to form
sophisticated conditional structures.
IF tests Condition(s) and, if true, executes IfStatement(s). If Condition(s) is false, the
following optional ELSEIF Condition(s), and/or ELSEIFNOT Condition(s), are tested, in order,
until a valid condition line is found, then the associated ElseIfStatement(s), or
ElseIfNotStatement(s), block is executed. The optional ElseStatement(s) block is executed if
no previous valid condition lines are found.
A “valid” condition is one that evaluates to TRUE for a positive conditional statement (IF or
ELSEIF) or evaluates to FALSE for a negative conditional statement (ELSEIFNOT).
Simple IF Statement
The most common form of the IF conditional command performs an action if, and only if, a
condition is true. This is written as an IF statement followed by one or more indented lines of
code. For example:
if X > 10 'If X is greater than 10
!outa[0] 'Toggle P0
!outa[1] 'Toggle P1
This example tests if X is greater than 10; if it is, I/O pin 0 is toggled. Whether or not the IF
condition was true, I/O pin P1 is toggled next.
Since the !outa[0] line is indented from the IF line, it belongs to the IfStatement(s) block
and is executed only if the IF condition is true. The next line, !outa[1], is not indented from
the IF line, so it is executed next whether or not the IF’s Condition(s) was true. Here’s
another version of the same example:
if X > 10 'If X is greater than 10
!outa[0] 'Toggle P0
!outa[1] 'Toggle P1
waitcnt(2_000 + cnt) 'Wait for 2,000 cycles
This example is very similar to the first, except there are now two lines of code indented from
the IF statement. In this case, if X is greater than 10, P0 is toggled then P1 is toggled and
finally the waitcnt line is executed. If, however, X was not greater than 10, the !outa[0] and
!outa[1] lines are skipped (since they are indented and part of the IfStatement(s) block) and
the waitcnt line is executed (since it is not indented; it is not part of the IfStatement(s) block).
Combining Conditions
The Condition(s) field is evaluated as one single Boolean condition, but it can be made up of
more than one Boolean expression by combining them with the AND and OR operators; see
pages 272-273. For example:
This IF statement would be true if, and only if, X is greater than 10 and X is also less than 100.
In other words, it’s true if X is in the range 11 to 99. Sometimes statements like these can be
a little difficult to read. To make it easier to read, parentheses can be used to group each sub-
condition, such as with the following.
if (X > 10) AND (X < 100)'If X greater than 10 and less than 100
Here, if X is greater than 100, I/O pin 0 is toggled, otherwise, X must be less than or equal to
100, and I/O pin 1 is toggled. This IF...ELSE construct, as written, always performs either a
toggle on P0 or a toggle on P1; never both, and never neither.
Remember, the code that logically belongs to the IfStatement(s) or the ElseStatement(s) must
be indented from the IF or the ELSE, respectively, by at least one space. Also note that the
ELSE must be lined up horizontally with the IF statement; they must both begin on the same
column or the compiler will not know that the ELSE goes with that IF.
For every IF statement, there can be zero or one ELSE component. ELSE must be the last
component in an IF statement, appearing after any potential ELSEIFs.
Here, if X is greater than 100, I/O pin 0 is toggled, otherwise, if X equals 90, I/O pin 1 is
toggled, and if neither of those conditions were true, neither P0 nor P1 is toggled. This is a
slightly shorter way of writing the following code:
if X > 100 'If X is greater than 100
!outa[0] 'Toggle P0
else 'Otherwise,
if X == 90 'If X = 90
!outa[1] 'Toggle P1
Both of these examples perform the same actions, but the first is shorter and is usually
considered easier to read. Note that the ELSEIF, just like the ELSE, must be lined up (start in
the same column) as the IF that it is associated with.
Each IF conditional statement can have zero or more ELSEIF statements associated with it.
Look at the following:
if X > 100 'If X is greater than 100
!outa[0] 'Toggle P0
elseif X == 90 'Else If X = 90
!outa[1] 'Toggle P1
elseif X > 50 'Else If X > 50
!outa[2] 'Toggle P2
We have three conditions and three possible actions here. Just like the previous example, if X
is greater than 100, P0 is toggled, otherwise, if X equals 90, P1 is toggled, but if neither of
those conditions were true and X is greater than 50, P2 is toggled. If none of those conditions
were true, then none of those actions would occur.
There is an important concept to note about this example. If X is 101 or higher, P0 is toggled,
or if X is 90, P1 is toggled, or if X is 51 to 89, or 91 to 100, P2 is toggled. This is because the
IF and ELSEIF conditions are tested, one at a time, in the order they are listed and only the
first condition that is true has its block of code executed; no further conditions are tested after
that. This means that if we had rearranged the two ELSEIFs so that the “X > 50” were checked
first, we’d have a bug in our code.
The above example contains an error because, while X could be equal to 90, the elseif X ==
90 statement would never be tested because the previous one, elseif X > 50, would be tested
first, and since it is true, its block is executed and no further conditions of that IF structure
are tested. If X were 50 or less, the last ELSEIF condition is tested, but of course, it will never
be true.
This is just like the example above, except that if none of the IF or ELSEIF conditions are true,
P3 is toggled.
IFNOT
Test condition(s) and execute a block of code if valid (negative logic).
((PUB ┆ PRI))
IFNOT Condition(s)
IfNotStatement(s)
〈 ELSEIF Condition(s)
ElseIfStatement(s) 〉…
〈 ELSEIFNOT Condition(s)
ElseIfNotStatement(s) 〉…
〈 ELSE
ElseStatement(s) 〉
Explanation
IFNOT is one of the three major conditional commands (IF, IFNOT, and CASE) that conditionally
executes a block of code. IFNOT is the complementary (negative) form of IF.
IFNOT tests Condition(s) and, if false, executes IfNotStatement(s). If Condition(s) is true, the
following optional ELSEIF Condition(s), and/or ELSEIFNOT Condition(s), are tested, in order,
until a valid condition line is found, then the associated ElseIfStatement(s), or
ElseIfNotStatement(s), block is executed. The optional ElseStatement(s) block is executed if
no previous valid condition lines are found.
A “valid” condition is one that evaluates to FALSE for a negative conditional statement (IFNOT,
or ELSEIFNOT) or evaluates to TRUE for a positive conditional statement (ELSEIF).
See IF on page 220 for information on the optional components of IFNOT.
INA, INB
Input Registers for 32-bit Ports A and B.
((PUB ┆ PRI))
INA 〈[Pin(s)]〉
((PUB ┆ PRI))
INB 〈[Pin(s)]〉 (Reserved for future use)
Returns: Current state of I/O Pin(s) for Port A or B.
Explanation
INA and INB are two of six registers (DIRA, DIRB, INA, INB, OUTA and OUTB) that directly affect
the I/O pins. The INA register contains the current states for each of the 32 I/O pins in Port A;
bits 0 through 31 correspond to P0 through P31. The INB register contains the current states
for each of the 32 I/O pins in Port B; bits 0 through 31 correspond to P32 through P63.
NOTE: INB is reserved for future use; the Propeller P8X32A does not include Port B I/O pins
so only INA is discussed below.
INA is read-only and is not really implemented as a register but rather is just an address that,
when accessed as a source item in an expression, reads the Port A I/O pins directly at that
moment. In the result, a low (0) bit indicates the corresponding I/O pin senses ground, and a
high (1) bit indicates the corresponding I/O pin senses VDD (3.3 volts). Since the Propeller
is a CMOS device, the I/O pins sense anything above ½ VDD to be high, so a high means the
pin senses approximately 1.65 volts or higher.
Each cog has access to all I/O pins at any given time. Essentially, all I/O pins are directly
connected to each cog so that there is no hub-related mutually-exclusive access involved.
Each cog has its own INA pseudo-register that gives it the ability to read the I/O pins states
(low or high) at any time. The actual I/O pins’ values are read, regardless of their designated
input or output direction.
Using INA
Read INA to get the state of I/O pins at that moment. The following example assumes Temp
was created elsewhere.
Temp := INA 'Get state of P0 through P31
This example reads the states of all 32 I/O pins of Port A into Temp.
Using the optional Pin(s) field, the cog can read one I/O pin (one bit) at a time. For example:
Temp := INA[16] 'Get state of P16
The above line reads I/O pin 16 and stores its state (0 or 1) in the lowest bit of Temp; all other
bits of Temp are cleared.
In Spin, the INA register supports a special form of expression, called a range-expression,
which allows you to read a group of I/O pins at once, without reading others outside the
specified range. To read multiple, contiguous I/O pins at once, use a range expression (like
x..y) in the Pin(s) field.
Temp := INA[18..15] 'Get states of P18:P15
Here, the lowest four bits of Temp (3, 2, 1, and 0) are set to the states of I/O pins 18, 17, 16,
and 15, respectively, and all other bits of Temp are cleared to 0.
IMPORTANT: The order of the values in a range-expression affects how it is used. For
example, the following swaps the order of the range from the previous example.
Temp := INA[15..18] 'Get states of P15:P18
Here, Temp bits 3, 2, 1, and 0 are set to the states of I/O pins 15, 16, 17, and 18, respectively.
This is a powerful feature of range-expressions, but if care is not taken it can also cause
strange, unintentional results.
((PUB ┆ PRI))
LOCKCLR ( ID )
Returns: Previous state of lock (TRUE or FALSE).
Explanation
LOCKCLR is one of four lock commands (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKCLR clears lock
ID to FALSE and retrieves the previous state of that lock (TRUE or FALSE).
See About Locks, page 230, and Suggested Rules for Locks, page 231 for information on the
typical use of locks and the LOCKxxx commands.
The following assumes that a cog (either this one or another) has already checked out a lock
using LOCKNEW and shared the ID with this cog, which saved it as SemID. It also assumes this
cog has an array of longs called LocalData.
PUB ReadResource | Idx
repeat until not lockset(SemID) 'wait until we lock the resource
repeat Idx from 0 to 9 'read all 10 longs of resource
LocalData[Idx] := long[Idx]
lockclr(SemID) 'unlock the resource
Both of these methods, ReadResource and WriteResource, follow the same rules before and
after accessing the resource. First, they wait indefinitely at the first repeat loop until it has
locked the resource; i.e.: it has successfully “set” the associated lock. If LOCKSET returns TRUE,
the condition “until not lockset…” is FALSE, meaning that some other cog is currently
accessing the resource, so that first repeat loop tries again. If LOCKSET returns FALSE, the
((PUB ┆ PRI))
LOCKNEW
Returns: ID (0-7) of the lock checked out, or -1 if none were available.
Explanation
LOCKNEW is one of four lock commands (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKNEW checks out
a unique lock, from the hub, and retrieves the ID of that lock. If no locks were available,
LOCKNEW returns -1.
About Locks
A lock is a semaphore mechanism that is used to communicate between to two or more
entities. In the Propeller chip, a lock is simply one of eight global bits in a protected register
within the Hub. The Hub maintains an inventory of which locks are in use and their current
states. Cogs can check out, set, clear, and return locks as needed during run time to indicate
whether a custom shared item, such as a block of memory, is available or not. Since locks
are managed by the Hub only one cog can affect them at a time, making this an effective
control mechanism.
In applications where two or more cogs are sharing the same memory, a tool such as a lock
may be required to prevent catastrophic collisions from occurring. The Hub prevents such
collisions from occurring on elemental data (such a byte, word or long) at every moment in
time, but it can not prevent “logical” collisions on blocks of multiple elements (such as a
block of bytes, words, longs or any combination of these). For example, if two or more cogs
are sharing a single byte of main memory, each one is guaranteed exclusive access to that
byte by nature of the Hub. But if those two cogs share multiple bytes of main memory, the
Hub can not prevent one cog from writing a few of those bytes while another cog is reading
all of them; all cogs’ interactions with those bytes may be interleaved in time. In this case,
the developer should design each process (in each cog that shares this memory) so that they
cooperatively share the memory block in a non-destructive way. Locks serve as flags that
notify each cog when a memory block is safe to manipulate or not.
PUB SetupSharedResource
<code to set up user-defined, shared resource here>
if (SemID := locknew) == -1
<error, no locks available>
else
<share SemID's value with other cogs>
The example above calls LOCKNEW and stores the result in SemID. If that result is -1, an error
occurs. If the SemID is not -1, then a valid lock was checked out and that SemID needs to be
shared with other cogs along with the address of the resource that SemID is used for. The
method used to communicate the SemID and resource address depends on the application, but
typically they are both passed as parameters to the Spin method that is launched into a cog, or
as the PAR parameter when launching an assembly routine into a cog. See COGNEW, page 189.
LOCKRET
Release lock back to lock pool, making it available for future LOCKNEW requests.
((PUB ┆ PRI))
LOCKRET ( ID )
Explanation
LOCKRET is one of four lock commands (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKRET returns a
lock, by ID, back to the Hub’s lock pool so that it may be reused by other cogs at a later time.
For example:
LOCKRET(2)
This example returns Lock 2 back to the Hub. This doesn’t prevent cogs from accessing
Lock 2 afterwards, it only allows the Hub to reassign it to cogs that call LOCKNEW in the future.
Applications should be written such that locks are not accessed with LOCKSET or LOCKCLR
unless they are currently checked out.
See About Locks, page 230, and Suggested Rules for Locks, page 231 for information on the
typical use of locks and the LOCKxxx commands.
Note that user-defined resources are not actually locked by either the Hub or the checked-out
lock. The lock feature only provides a means for objects to cooperatively lock those
resources. It’s up to the objects themselves to decide on, and abide by, the rules of lock use
and what resource(s) will be governed by them. Additionally, the Hub does not directly
assign a lock to the cog that called LOCKNEW, rather it simply marks it as being “checked out”
by a cog; any other cog can “return” locks to the pool of available locks. Also, any cog can
access any lock through the LOCKCLR and LOCKSET commands even if those locks were never
checked out. Doing such things is generally not recommended because of the havoc it can
cause with other, well-behaved objects in the application.
See LOCKNEW, page 230; LOCKCLR, page 228; and LOCKSET, page234 for more information.
((PUB ┆ PRI))
LOCKSET ( ID )
Returns: Previous state of lock (TRUE or FALSE).
Explanation
LOCKSET is one of four lock commands (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKSET sets lock ID
to TRUE and retrieves the previous state of that lock (TRUE or FALSE).
See About Locks, page 230, and Suggested Rules for Locks, page 231 for information on the
typical use of locks and the LOCKxxx commands.
The following assumes that a cog (either this one or another) has already checked out a lock
using LOCKNEW and shared the ID with this cog, which saved it as SemID. It also assumes this
cog has an array of longs called LocalData.
PUB ReadResource | Idx
repeat until not lockset(SemID) 'wait until we lock the resource
repeat Idx from 0 to 9 'read all 10 longs of resource
LocalData[Idx] := long[Idx]
lockclr(SemID) 'unlock the resource
Both of these methods, ReadResource and WriteResource, follow the same rules before and
after accessing the resource. First, they wait indefinitely at the first repeat loop until it has
locked the resource; i.e.: it has successfully “set” the associated lock. If LOCKSET returns TRUE,
the condition “until not lockset…” is false, meaning that some other cog is currently
accessing the resource, so that first repeat loop tries again. If LOCKSET returns FALSE, the
VAR
LONG Symbol 〈[Count ]〉
DAT
LONG Data
((PUB ┆ PRI))
LONG [BaseAddress] 〈[Offset ]〉
Explanation
LONG is one of three multi-purpose declarations (BYTE, WORD, and LONG) that declares or
operates on memory. LONG can be used to:
1) declare a long-sized (32-bit) symbol or a multi-long symbolic array in a VAR block, or
2) declare long-aligned, and/or long-sized, data in a DAT block, or
3) read or write a long of main memory at a base address with an optional offset.
The above example declares two variables (symbols), Temp and List. Temp is simply a single,
long-sized variable. The line under the Temp declaration uses the optional Count field to
create an array of 25 long-sized variable elements called List. Both Temp and List can be
Page 236 · Propeller Manual v1.0
4: Spin Language Reference – LONG
accessed from any PUB or PRI method within the same object that this VAR block was declared;
they are global to the object. An example of this is below.
PUB SomeMethod
Temp := 25_000_000 'Set Temp to 25,000,000
List[0] := 500_000 'Set first element of List to 500,000
List[1] := 9_000 'Set second element of List to 9,000
List[24] := 60 'Set last element of List to 60
For more information about using LONG in this way, refer to the VAR section’s Variable
Declarations (Syntax 1) on page 315, and keep in mind that LONG is used for the Size field in
that description.
The above example declares two data symbols, MyData and MyList. MyData points to the start
of long-aligned and long-sized data in main memory. MyData’s values, in main memory, are
640,000 and $0000BB50, respectively. MyList uses a special DAT block syntax of LONG that
creates a byte-aligned but long-sized set of data in main memory. MyList’s values, in main
memory, are $FF995544 and 1,000, respectively. When accessed a byte at a time, MyList
contains $44, $55, $99, $FF, 232 and 3, 0 and 0 since the data is stored in little-endian
format.
Note: MyList could have been defined as word-aligned, long-sized data if the “byte”
reference were replaced with “word”.
This data is compiled into the object and resulting application as part of the executable code
section and may be accessed using the read/write form, syntax 3, of LONG (see below). For
more information about using LONG in this way, refer to the DAT section’s Declaring Data
(Syntax 1) on page 208, and keep in mind that LONG is used for the Size field in that
description.
The first line inside of the GetData method, Temp := MyData, reads the first value in the
MyData list (the long-sized value 640,000) and stores it in Temp. Further down, in the REPEAT
loop, the Temp := MyList[Index] line reads a byte of main memory from the location of
MyList + Index. The first time through the loop (Index = 0) the value $44 ($FF995544’s
byte 0) is read from MyList and the second time through the loop (Index = 1) the next byte is
read, $55 ($FF995544’s byte 1). Why were bytes read instead of longs? MyList points at the
start of our desired data and our data was specified as long-sized data but the symbol MyList
is treated as a byte pointer since that data was specified to be byte-aligned.
Perhaps you intended to read long-sized data from MyList just like we did from MyData.
Coincidentally, even though MyList is declared as byte-aligned long data, it is also happens
to be long-aligned as well because the previous declaration finished on a long boundary. This
fact allows us to use the LONG declaration to achieve our goal.
PUB GetData | Index, Temp
Temp := LONG[@MyData] 'Read first long of MyData into Temp
<do something with Temp> 'Perform task with Temp
In this example, the first line inside of the GetData method uses the LONG declaration to read a
long of main memory from the address of MyData and stores it in Temp, in this case, the value
640,000. Further down, in the REPEAT loop, the LONG declaration reads a long of main
memory from the address of MyList + Index and stores it in Temp. Since the first iteration of
Page 238 · Propeller Manual v1.0
4: Spin Language Reference – LONG
the loop has Index set to 0, the first long of MyList is read, $FF995544. The next time
through the loop it reads the next long, effectively @MyList + 1 (the 1,000).
Note that if the data was not long-aligned, either intentionally or coincidentally, we’d have
different results from the REPEAT loop just described. For example, if MyList happened to be
shifted forward by one byte, the first value read by the loop would be $995544xx; where xx is
an unknown byte-sized value. Similarly, the second value read would be 256255; made up of
the $FF from the upper byte of MyList’s first value, and the 3 and 232 from the lower two
bytes of MyList’s second value. Make sure to pay close attention to data value alignments in
memory to avoid this likely unintentional result.
Using a similar syntax, longs of main memory can be written to as well, as long as they are
RAM locations. For example:
LONG[@MyList][0] := 2_000_000_000 'Write 2 billion to first word
'of MyList
This line writes the value 2,000,000,000 to the first long of data at MyList.
((PUB ┆ PRI))
LONGFILL(StartAddress, Value, Count )
• StartAddress is an expression indicating the location of the first long of memory to fill
with Value.
• Value is an expression indicating the value to fill longs with.
• Count is an expression indicating the number of longs to fill, starting with
StartAddress.
Explanation
LONGFILL is one of three commands (BYTEFILL, WORDFILL, and LONGFILL) used to fill blocks of
main memory with a specific value. WORDFILL fills Count longs of main memory with Value,
starting at location StartAddress.
Using LONGFILL
LONGFILL is a great way to clear large blocks of long-sized memory. For example:
VAR
long Buff[100]
PUB Main
longfill(@Buff, 0, 100) 'Clear Buff to 0
The first line of the Main method, above, clears the entire 100-long (400-byte) Buff array to
all zeros. LONGFILL is faster at this task than a dedicated REPEAT loop is.
LONGMOVE
Copy longs from one region to another in main memory.
((PUB ┆ PRI))
LONGMOVE (DestAddress, SrcAddress, Count )
• DestAddress is an expression specifying the main memory location to copy the first
long of source to.
• SrcAddress is an expression specifying the main memory location of the first long of
source to copy.
• Count is an expression indicating the number of longs of the source to copy to the
destination.
Explanation
LONGMOVE is one of three commands (BYTEMOVE, WORDMOVE, and LONGMOVE) used to copy blocks
of main memory from one area to another. LONGMOVE copies Count longs of main memory
starting from SrcAddress to main memory starting at DestAddress.
Using LONGMOVE
LONGMOVE is a great way to copy large blocks of long-sized memory. For example:
VAR
long Buff1[100]
long Buff2[100]
PUB Main
longmove(@Buff2, @Buff1, 100) 'Copy Buff1 to Buff2
The first line of the Main method, above, copies the entire 100-long (400-byte) Buff1 array to
the Buff2 array. LONGMOVE is faster at this task than a dedicated REPEAT loop is.
((PUB ┆ PRI))
LOOKDOWN ( Value : ExpressionList )
((PUB ┆ PRI))
LOOKDOWNZ ( Value : ExpressionList )
Returns: One-based index position (LOOKDOWN) or a zero-based index position (LOOKDOWNZ) of
Value in ExpressionList, or 0 if Value not found.
Explanation
LOOKDOWN and LOOKDOWNZ are commands that retrieve indexes of values from a list of values.
LOOKDOWN returns the one-based index position (1..N) of Value from ExpressionList.
LOOKDOWNZ is just like LOOKDOWN except it returns the zero-based index position (0..N−1). For
both commands, if Value is not found in ExpressionList then 0 is returned.
The GetIndex method in this example uses LOOKDOWN to find Value and returns the index
where it was found in the ExpressionList, or 0 if not found. The ShowList method calls
GetIndex repeatedly with different values and prints the resulting index on a display.
Assuming Print is a method that displays a value, this example will print 1, 2, 3, 4, 5, 6 and 7
on a display.
If LOOKDOWNZ were used instead of LOOKDOWN this example would print 0, 1, 2, 3, 4, 5, and 6 on
a display.
If Value is not found, LOOKDOWN, or LOOKDOWNZ, returns 0. So if one of the lines of the ShowList
method was, Print(GetIndex(50)), the display would show 0 at the time it was executed.
If using LOOKDOWNZ, keep in mind that it may return 0 if either Value was not found or Value is
at index 0. Make sure this will not cause an error in your code or use LOOKDOWN instead.
((PUB ┆ PRI))
LOOKUP ( Index : ExpressionList )
((PUB ┆ PRI))
LOOKUPZ ( Index : ExpressionList )
Returns: Value at the one-based Index position (LOOKUP) or zero-based Index position
(LOOKUPZ) of ExpressionList, or 0 if out-of-range.
Explanation
LOOKUP and LOOKUPZ are commands that retrieve entries from a list of values. LOOKUP returns
the value from ExpressionList that is located in the one-based position (1..N) given by Index.
LOOKUPZ is just like LOOKUP except it uses a zero-based Index (0..N-1). For both commands, if
Index is out of range then 0 is returned.
This example looks up all the values in LOOKUP’s ExpressionList and displays them. The
REPEAT loop counts with Index from 1 to 7. Each iteration of the loop, LOOKUP uses Index to
retrieve a value from its list. If Index equals 1, the value 25 is returned. If Index equals 2, the
value 300 is returned. Assuming Print is a method that displays the value of Temp, this
example will print 25, 300, 2510, 163, 17, 8000 and 3 on a display.
Page 244 · Propeller Manual v1.0
4: Spin Language Reference – LOOKUP, LOOKUPZ
If LOOKUPZ is used, the list is zero-based (0..N-1) instead of one-based; an Index of 0 returns
25, Index of 1 returns 300, etc.
If Index is out of range 0 is returned. So, for LOOKUP, if the REPEAT statement went from 0 to
8, instead of 1 to 7, this example would print 0, 25, 300, 2510, 163, 17, 8000, 3 and 0 on a
display.
((PUB ┆ PRI))
NEXT
Explanation
NEXT is one of two commands (NEXT and QUIT) that affect REPEAT loops. NEXT causes any
further statements in the REPEAT loop to be skipped and the next iteration of the loop to be
started thereafter.
Using NEXT
NEXT is typically used as an exception case, in a conditional statement, in REPEAT loops to
move immediately to the next iteration of the loop. For example, assume that X is a variable
created earlier and Print() is a method created elsewhere that prints a value on a display:
repeat X from 0 to 9 'Repeat 10 times
if X == 4
next 'Skip if X = 4
byte[$7000][X] := 0 'Clear RAM locations
Print(X) 'Print X on screen
The above code iteratively clears RAM locations and prints the value of X on a display, but
with one exception. If X equals 4, the IF statement executes the NEXT command which causes
the loop to skip remaining lines and go right to the next iteration. This has the effect of
clearing RAM locations $7000 through $7003 and locations $7005 through $7009 and
printing 0, 1, 2, 3, 5, 6, 7, 8, 9 on the display.
The NEXT command can only be used within a REPEAT loop; an error will occur otherwise.
OBJ
Declare an Object Block.
OBJ
Symbol 〈[Count]〉: "ObjectName" 〈 Symbol 〈[Count]〉: "ObjectName"〉…
Explanation
The Object Block is a section of source code that declares which objects are used and the
object symbols that represent them. This is one of six special declarations (CON, VAR, OBJ, PUB,
PRI, and DAT) that provide inherent structure to the Spin language.
Object declarations begin with OBJ on a line by itself followed by one or more declarations.
OBJ must start in column 1 (the leftmost column) of the line it is on and we recommend the
lines following be indented by at least one space. For example:
OBJ
Num : "Numbers"
Term : "TV_Terminal"
This example defines Num as an object symbol of type "Numbers" and Term as an object
symbol of type "TV_Terminal". Public and Private methods can then refer to these objects
using the object symbols as in the following example.
PUB Print | S
S := Num.ToStr(LongVal, Num#DEC)
Term.Str(@S)
This public method, Print, calls the Numbers’ ToStr method and also the TV_Terminal’s Str
method. It does this by using the Num and Term object symbols followed by the Object-
This example declares PWM as an array of two objects (two instances of the same object). The
object itself just happens to be called “PWM” as well. The public method, GenPWM, calls the
Start method of each instance using indexes 0 and 1 with the object symbol array, PWM.
Both instances of the PWM object are compiled into the application such that there is one copy
of its program code (PUBs, PRIs, and DATs) and two copies of its variable blocks (VARs). This
is because, for each instance, the code is the same but each instance needs its own variable
space so it can operate independent of the other.
An important point to consider with multiple instances of an object is that there is only one
copy of its DAT block because it may contain Propeller Assembly code. DAT blocks can also
contain initialized data and regions set aside for workspace purposes, all with symbolic
names. Since there is only one copy of it for multiple instances of an object, that area is
shared among all instances. This provides a convenient way to create shared memory
between multiple instances of a particular object.
Operators
The Propeller chip features a powerful set of math and logic operators. A subset of these
operators is supported by the Propeller Assembly language; however, since the Spin language
has a use for every form of operator supported by the Propeller, this section describes every
operator in detail. Please see the Operators section on page 390 for a list of operators
available in Propeller Assembly.
Expression Workspace
The Propeller is a 32-bit device and, unless otherwise noted, expressions are always evaluated
using 32-bit, signed integer math. This includes intermediate results as well. If any
intermediate result overflows or underflows a 32-bit signed integer (above 2,147,483,647 or
below -2,147,483,648), the final result of the expression will not be as expected. A
workspace of 32 bits provides lots of room for intermediate results but it is still wise to keep
overflow/underflow possibilities in mind.
If fractional underflow is an issue, or if real numbers rather than integers are desired in an
expression, floating-point support can help. The compiler supports 32-bit floating-point
values and constant expressions with many of the same math operators as it does for integer
constant expressions. Note that this is for constant expressions only, not run time variable
expressions. For floating-point run-time expressions, the Propeller chip provides support
through the FloatMath object supplied with the software installation. See Constant
Assignment ‘=’, page 254; FLOAT, page 216; ROUND, page 303; and TRUNC, page 314, as well
as the FloatMath and FloatString objects for more information
Operator Attributes
The operators have the following important attributes, each of which is shown in the
following two tables and further explained afterwards:
• Unary / Binary
• Normal / Assignment
• Constant and/or Variable Expression
• Level of Precedence
Unary / Binary
Each operator is either unary or binary in nature. Unary operators are those that operate on
only one operand. For example:
!Flag ' bitwise NOT of Flag
^^Total ' square root of Total
Binary operators are those that operate on two operands. For example:
X + Y ' add X and Y
Num << 4 ' shift Num left 4 bits
Note that the term “binary operator” means “two operands,” and has nothing to do with
binary digits. To distinguish operators whose function relates to binary digits, we’ll use the
term “bitwise” instead.
Normal / Assignment
Normal operators, like Add ‘+’ and Shift Left ‘<<’, operate on their operand(s) and provide
the result for use by the rest of the expression, without affecting the operand or operands
themselves. Those that are assignment operators, however, write their result to either the
variable they operated on (unary), or to the variable to their immediate left (binary), in
addition to providing the result for use by the rest of the expression.
Binary operators have special forms that end in equal ‘=’ to make them assignment operators.
Unary operators do not have a special assignment form; some always assign while others
assign only in special situations. See Table 4-9 below and the operator’s explanation, for
more information.
Level of Precedence
Each operator has an assigned level of precedence that determines when it will take action in
relation to other operators within the same expression. For example, it is commonly known
that Algebraic rules require multiply and divide operations to be performed before add and
subtract operations. The multiply and divide operators are said to have a “higher level of
precedence” than add and subtract. Additionally, multiply and divide are commutable; both
are on the same precedence level, so their operations result in the same value regardless of the
order it is performed (multiply first, then divide, or vice versa). Commutative operators are
always evaluated left to right except where parentheses override that rule.
The Propeller chip applies the order-of-operations rules as does Algebra: expressions are
evaluated left-to-right, except where parentheses and differing levels of precedence exist.
Following these rules, the Propeller will evaluate:
X = 20 + 8 * 4 – 6 / 2
...to be equal to 49; that is, 8 * 4 = 32, 6 / 2 = 3, and 20 + 32 – 3 = 49. If you wish the
expression to be evaluated differently, use parentheses to enclose the necessary portions of
the expression.
Intermediate Assignments
The Propeller chip’s expression engine allows for, and processes, assignment operators at
intermediate stages. This is called “intermediate assignments” and it can be used to perform
complex calculations in less code. For example, the following equation relies heavily on X,
and X + 1.
X := X - 3 * (X + 1) / ||(X + 1)
The same statement could be rewritten, taking advantage of the intermediate assignment
property of the increment operator:
X := X++ - 3 * X / ||X
Assuming X started out at -5, both of these statements evaluate to -2, and both store that value
in X when done. The second statement, however, does it by relying on an intermediate
assignment (the X++ part) in order to simplify the rest of the statement. The Increment
operator ‘++’ is evaluated first (highest precedence) and increments X’s -5 to -4. Since this is
a “post increment” (see Increment, pre- or post- ‘+ +’, page 257) it first returns X’s original
value, -5, to the expression and then writes the new value, -4, to X. So, the “X++ - 3…” part
of the expression becomes “-5 – 3…” Then the absolute, multiply, and divide operators are
evaluated, but the value of X has been changed, so they use the new value, -4, for their
operations:
-5 – 3 * -4 / ||-4 → -5 – 3 * -4 / 4 → -5 – 3 * -1 → -5 – -3 = -2
Occasionally, the use of intermediate assignments can compress multiple lines of expressions
into a single expression, resulting in slightly smaller code size and slighter faster execution.
The remaining pages of this section further explain each math and logic operator shown in
Table 4-9 in the same order shown.
This code sets the symbol _xinfreq to 4,096,000 and the symbol WakeUp to %00110000.
Throughout the rest of the program the compiler will use these numbers in place of their
respective symbols. See CON, page 194.
These declarations are constant expressions, so many of the normal operators can be used to
calculate a final constant value at compile time. For example, it may be clearer to rewrite the
above example as follows:
CON
_xinfreq = 4096000
Reset = %00100000
Initialize = %00010000
WakeUp = Reset & Initialize
Here, WakeUp is still set to %00110000 at compile time, but it is now more obvious to future
readers that the WakeUp symbol contains the binary codes for a Reset and an Initialize
sequence for that particular application.
The above examples create 32-bit signed integer constants; however, it is also possible to
create 32-bit floating-point constants. To do so, the expression must be expressed as a
floating-point value in one of three ways: 1) as an integer value followed by a decimal point
and at least one digit, 2) as an integer with an E followed by an exponent value, or 3) both 1
and 2 For example:
CON
OneHalf = 0.5
Ratio = 2.0 / 5.0
Miles = 10e5
The above code creates three floating-point constants. OneHalf is equal to 0.5, Ratio is equal
to 0.4 and Miles is equal to 1,000,000. Note that if Ratio were defined as 2 / 5 instead of 2.0
/ 5.0, the expression would be treated as an integer constant and the result would be an integer
constant equal to 0. For floating-point constant expressions, every value within the
At run time this code would set the Temp variable equal to 21 and set Triple to 21 * 3, which
is 63.
As with other assignment operators, the Variable Assignment operator can be used within
expressions to assign intermediate results, such as:
Triple := 1 + (Temp := 21) * 3
This example first sets Temp to 21, then multiplies Temp by 3 and adds 1, finally assigning the
result, 64, to Triple.
Add has an assignment form, +=, that uses the variable to its left as both the first operand and
the result destination.
For example,
Propeller Manual v1.0 · Page 255
Operators – Spin Language Reference
X += 10 'Short form of X := X + 10
Here, the value of X is added to 10 and the result is stored back in X. The assignment form of
Add may also be used within expressions for intermediate results; see Intermediate
Assignments, page 253.
Subtract has an assignment form, -=, that uses the variable to its left as both the first operand
and the result destination. For example,
X -= 10 'Short form of X := X - 10
Here, 10 is subtracted from the value of X and the result is stored back in X. The assignment
form of subtract may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Negate becomes an assignment operator when it is the sole operator to the left of a variable
on a line by itself. For example:
-A
This would negate the value of A and store the result back to A.
The above shows the pre-decrement form; it means “decrement before providing the value for
the next operation”. It decrements the value of X by one, writes that result to X and provides
that result to the rest of the expression. If X started out as 5 in this example, --X would store 4
in X, then the expression, 4 + 2 is evaluated, finally writing the result, 6, into Y. After this
statement, X equals 4 and Y equals 6.
Y := X-- + 2
The above shows the post-decrement form; it means “decrement after providing the value for
the next operation”. It provides the current value of X for the next operation in the
expression, then decrements the value of X by one and writes that result to X. If X began as 5
in this example, X-- would provide the current value for the expression (5 + 2) to be
evaluated later, then would store 4 in X. The expression 5 + 2 is then evaluated and the result,
7, is stored into Y. After this statement, X equals 4 and Y equals 7.
Since Decrement is always an assignment operator, the rules of Intermediate Assignments
(see page 253) apply here. Assume X started out as 5 for the following examples.
Y := --X + X
Here, X’s current value, 5, is saved for the next operation (the Add) and X itself is
decremented to 4, then 5 + 4 is evaluated and Y is set to 9.
The above shows the pre-increment form; it means “increment before providing the value for
the next operation”. It increments the value of X by one, writes that result to X and provides
that result to the rest of the expression. If X started out as 5 in this example, ++X would store
6 in X, then the expression, 6 - 4 is evaluated, finally writing the result, 2, into Y. After this
statement, X equals 6 and Y equals 2.
Y := X++ - 4
The above shows the post-increment form; it means “increment after providing the value for
the next operation”. It provides the current value of X for the next operation in the
expression, then increments the value of X by one and writes that result to X. If X started out
as 5 in this example, X++ would provide the current value for the expression (5 - 4) to be
evaluated later, then would store 6 in X. The expression 5 - 4 is then evaluated and the result,
1, is stored into Y. After this statement, X equals 6 and Y equals 1.
Since Increment is always an assignment operator, the rules of Intermediate Assignments (see
page 253) apply here. Assume X started out as 5 for the following examples.
Y := ++X + X
Here, X’s current value, 5, is saved for the next operation (the Add) and X itself is incremented
to 6, then 5 + 6 is evaluated and Y is set to 11.
Multiply-Low has an assignment form, *=, that uses the variable to its left as both the first
operand and the result destination. For example,
X *= 20 'Short form of X := X * 20
Here, the value of X is multiplied by 20 and the lowest 32 bits of the result is stored back in X.
The assignment form of Multiply-Low may also be used within expressions for intermediate
results; see Intermediate Assignments, page 253.
If Y started out as 536,870,912 (229) then Y ** 8 equals 1; the value in the upper 32 bits of the
result.
Multiply-High has an assignment form, **=, that uses the variable to its left as both the first
operand and the result destination. For example,
X **= 20 'Short form of X := X ** 20
Here, the value of X is multiplied by 20 and the upper 32 bits of the result is stored back in X.
The assignment form of Multiply-High may also be used within expressions for intermediate
results; see Intermediate Assignments, page 253.
Divide has an assignment form, /=, that uses the variable to its left as both the first operand
and the result destination. For example,
X /= 20 'Short form of X := X / 20
Propeller Manual v1.0 · Page 259
Operators – Spin Language Reference
Here, the value of X is divided by 20 and the integer result is stored back in X. The
assignment form of Divide may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Here, the value of X is divided by 20 and the 32-bit integer remainder is stored back in X. The
assignment form of Modulus may also be used within expressions for intermediate results;
see Intermediate Assignments, page 253.
The above example subtracts 5 from Y and limits the result to a minimum value to 100. If Y is
120 then 120 – 5 = 115; it is greater than 100 so X is set to 115. If Y is 102 then 102 – 5 = 97;
it is less than 100 so X is set to 100 instead.
Limit Minimum has an assignment form, #>=, that uses the variable to its left as both the first
operand and the result destination. For example,
X #>= 50 'Short form of X := X #> 50
Here, the value of X is limited to a minimum value of 50 and the result is stored back in X.
The assignment form of Limit Minimum may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
Page 260 · Propeller Manual v1.0
4: Spin Language Reference – Operators
Limit Maximum ‘<#’, ‘<#=’
The Limit Maximum operator compares two values and returns the lowest value. Limit
Maximum can be used in both variable and constant expressions. Example:
X := Y + 21 <# 250
The above example adds 21 to Y and limits the result to a maximum value to 250. If Y is 200
then 200 + 21 = 221; it is less than 250 so X is set to 221. If Y is 240 then 240 + 21 = 261; it is
greater than 250 so X is set to 250 instead.
Limit Maximum has an assignment form, <#=, that uses the variable to its left as both the first
operand and the result destination. For example,
X <#= 50 'Short form of X := X <# 50
Here, the value of X is limited to a maximum value of 50 and the result is stored back in X.
The assignment form of Limit Minimum may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
Square Root becomes an assignment operator when it is the sole operator to the left of a
variable on a line by itself. For example:
^^Y
This would store the square root of the value of Y back into Y.
The Sign-Extend 7 operator in this example extends the sign of the value, X in this case, from
bit 7 up to bit 31. A 32-bit signed integer is stored in twos-complement form and the most
significant bit (31) indicates the sign of the value (positive or negative). There may be times
where calculations on simple data result in byte-sized values that should be treated as a
signed integer in the range of -128 to +127. When you need to perform further calculations
with those byte-sized values, use the Sign-Extend 7 operator to convert the number into the
proper 32-bit signed integer form. In the above example, assume X represents the value -20,
which in 8-bit twos-complement form is actually the value 236 (%11101100). The ~X portion
of the expression extends the sign bit from bit 7 all the way up to bit 31, converting the
number to the proper 32-bit twos-complement form of -20 (%11111111 11111111 11111111
11101100). Adding that sign-extended value to 25 results in 5, the intended result, whereas it
would have resulted in 261 without the proper sign extension.
The following is an example of the Post-Clear operator form.
Y := X~ + 2
The Post-Clear operator in this example clears the variable to 0 (all bits low) after providing
its current value for the next operation. In this example if X started out as 5, X~ would provide
the current value for the expression (5 + 2) to be evaluated later, then would store 0 in X. The
The Sign-Extend 15 operator in this example extends the sign of the value, X in this case,
from bit 15 up to bit 31. A 32-bit signed integer is stored in twos-complement form and the
most significant bit (31) indicates the sign of the value (positive or negative). There may be
times where calculations on simple data result in word-sized values that should be treated as a
signed integer in the range of -32768 to +32767. When you need to perform further
calculations with those word-sized values, use the Sign-Extend 15 operator to convert the
number into the proper 32-bit signed integer form. In the above example, assume X
represents the value -300, which in 16-bit twos-complement form is actually the value 65,236
(%11111110 11010100). The ~~X portion of the expression extends the sign bit from bit 15
all the way up to bit 31, converting the number to the proper 32-bit twos-complement form of
-300 (%11111111 11111111 11111110 11010100). Adding that sign-extended value to 50
results in -250, the intended result, whereas it would have resulted in 65,286 without the
proper sign extension.
The following is an example of the Post-Set operator form.
Y := X~~ + 2
The Post-Set operator in this example sets the variable to -1 (all bits high) after providing its
current value for the next operation. In this example if X started out as 6, X~~ would provide
the current value for the expression (6 + 2) to be evaluated later, then would store -1 in X.
The expression 6 + 2 is then evaluated and the result, 8, is stored into Y. After this statement,
X equals -1 and Y equals 8.
Since Sign-Extend 15 and Post-Set are always assignment operators, the rules of Intermediate
Assignments apply to them (see page 253).
Propeller Manual v1.0 · Page 263
Operators – Spin Language Reference
Shift Arithmetic Right ‘~>’, ‘~>=’
The Shift Arithmetic Right operator is just like the Shift Right operator except that it
maintains the sign, like a divide by 2, 4, 8, etc on a signed value. Shift Arithmetic Right can
be used in variable and integer constant expressions, but not in floating-point constant
expressions. Example:
X := Y ~> 4
The above example shifts Y right by 4 bits, maintaining the sign. If Y is -3200 (%11111111
11111111 11110011 10000000) then -3200 ~> 4 = -200 (%11111111 11111111 11111111
00111000). If the same operation had been done with the Shift Right operator instead, the
result would have been 268,435,256 (%00001111 11111111 11111111 00111000).
Shift Arithmetic Right has an assignment form, ~>=, that uses the variable to its left as both
the first operand and the result destination. For example,
X ~>= 2 'Short form of X := X ~> 2
Here, the value of X is shifted right 2 bits, maintaining the sign, and the result is stored back
in X. The assignment form of Shift Arithmetic Right may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
Random ‘?’
The Random operator is a special, immediate operator that uses a variable’s value as a seed to
create a pseudo random number and assigns that number to the same variable. It can only be
used in run-time variable expressions. Random has two forms, forward and reverse,
depending on which side of the variable it appears on. The forward form appears to the left
of a variable and the reverse form appears to the right of a variable.
Random generates pseudo-random numbers ranging from -2,147,483,648 to +2,147,483,647.
It’s called “pseudo-random” because the numbers appear random, but are really generated by
a logic operation that uses a “seed” value as a tap into a sequence of over 4 billion essentially
random numbers. If the same seed value is used again, the same sequence of numbers is
generated. The Propeller chip’s Random output is reversible; in fact, specifically it is a 32-bit
maximum-length, four-tap LFSR (Linear Feedback Shift Register) with taps in both the LSB
(Least Significant Bit, rightmost bit) and the MSB (Most Significant Bit, leftmost bit)
allowing for bi-directional operation.
Think of the pseudo-random sequence it generates as simply a static list of over 4 billion
numbers. Starting with a particular seed value and moving forward results in a list of a
specific set of numbers. If, however, you took that last number generated and used it as the
Page 264 · Propeller Manual v1.0
4: Spin Language Reference – Operators
first seed value moving backward, you would end up with a list of the same numbers as
before, but in the reverse order. This is handy in many applications.
Here’s an example:
?X
The above shows the Random forward form; it uses X’s current value to retrieve the next
pseudo-random number in the forward direction and stores that number back in X. Executing
?X again results in yet a different number, again stored back into X.
X?
The above shows the Random reverse form; it uses X’s current value to retrieve the next
pseudo-random number in the reverse direction and stores that number back in X. Executing
X? again results in yet a different number, again stored back into X.
Since Random is always an assignment operator, the rules of Intermediate Assignments apply
to it (see page 253).
The above example sets Pin equal to the 32-bit value whose single high-bit corresponds to the
position indicated by PinNum.
If PinNum is 3, Pin is set equal to %00000000 00000000 00000000 00001000.
If PinNum is 31, Pin is set equal to %10000000 00000000 00000000 00000000.
There are many uses for Bitwise Decode, but one of the most useful is to convert from an I/O
pin number to the 32-bit pattern that describes that pin number in relation to the I/O registers.
For example, Bitwise Decode is very handy for the mask parameter of the WAITPEQ and
WAITPNE commands.
Bitwise Decode becomes an assignment operator when it is the sole operator to the left of a
variable on a line by itself. For example:
|<PinNum
Propeller Manual v1.0 · Page 265
Operators – Spin Language Reference
This would store the decoded value of PinNum back into PinNum.
The above example sets PinNum equal to the number of the highest bit set in Pin, plus 1.
If Pin is %00000000 00000000 00000000 00000000, PinNum is set equal to 0; no bits are set.
If Pin is %00000000 00000000 00000000 10000000, PinNum is set equal to 8; bit 7 is set.
If Pin is %10000000 00000000 00000000 00000000, PinNum is set equal to 32; bit 31 is set.
If Pin is %00000000 00010011 00010010 00100000, PinNum is set equal to 21; bit 20 is the
highest bit set.
Here, the value of X is shifted right two bits and is stored back in X. The assignment form of
Bitwise Shift Right may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Here, the value of X is rotated left one bit and is stored back in X. The assignment form of
Bitwise Rotate Left may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Here, the value of X is rotated right three bits and is stored back in X. The assignment form of
Bitwise Rotate Right may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Here, the eight LSBs of the value of X are reversed, all other bits are set to zero and the result
is stored back in X. The assignment form of Bitwise Reverse may also be used within
expressions for intermediate results; see Intermediate Assignments, page 253.
Example:
X := %00101100 & %00001111
Here, the value of X is ANDed with $F and the result is stored back in X. The assignment
form of Bitwise AND may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Be careful not to get Bitwise AND ‘&’ confused with Boolean AND ‘AND’. Bitwise AND is
for bit manipulation while Boolean AND is for comparison purposes (see page 272).
Example:
X := %00101100 | %00001111
The above example ORs %00101100 with %00001111 and writes the result, %00101111, to
X.
Bitwise OR has an assignment form, |=, that uses the variable to its left as both the first
operand and the result destination. For example,
X |= $F 'Short form of X := X | $F
Example:
X := %00101100 | %00001111
The above example XORs %00101100 with %00001111 and writes the result, %00100011,
to X.
Bitwise XOR has an assignment form, ^=, that uses the variable to its left as both the first
operand and the result destination. For example,
X ^= $F 'Short form of X := X ^ $F
Here, the value of X is XORed with $F and the result is stored back in X. The assignment
form of Bitwise XOR may also be used within expressions for intermediate results; see
Intermediate Assignments, page 253.
Example:
X := !%00101100
The above example NOTs %00101100 and writes the result, %11010011, to X.
Bitwise NOT becomes an assignment operator when it is the sole operator to the left of a
variable on a line by itself. For example:
!Flag
This would store the inverted value Flag back into Flag.
Be careful not to get Bitwise NOT ‘!’confused with Boolean NOT ‘NOT’. Bitwise NOT is for
bit manipulation while Boolean NOT is for comparison purposes (see page 274).
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if both Y and Z are non-zero, or FALSE (0) if either Y or Z are zero. During the comparison, it
promotes each of the two values to -1 if they are non-zero, making any value, other than 0, a -
1, so that the comparison becomes: “If Y is true and Z is true…”
This example evaluates the result of Y == 20 against that of Z == 100, and if both are true, the
Boolean AND operator returns TRUE (-1).
Boolean AND has an assignment form, AND=, that uses the variable to its left as both the first
operand and the result destination. For example,
X AND= True 'Short form of X := X AND True
Here, the value of X is promoted to TRUE if it is non-zero, then is compared with TRUE and the
Boolean result (TRUE / FALSE, -1 / 0) is stored back in X. The assignment form of Boolean
AND may also be used within expressions for intermediate results; see Intermediate
Assignments, page 253.
Be careful not to get Boolean AND ‘AND’ confused with Bitwise AND ‘&’. Boolean AND is
for comparison purposes while Bitwise AND is for bit manipulation (see page 269).
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if either Y or Z are non-zero, or FALSE (0) if both Y and Z are zero. During the comparison, it
promotes each of the two values to -1 if they are non-zero, making any value, other than 0, a -
1, so that the comparison becomes: “If Y is true or Z is true…”
Quite often this operator is used in combination with other comparison operators, such as in
the following example.
IF (Y == 1) OR (Z > 50)
This example evaluates the result of Y == 1 against that of Z > 50, and if either are true, the
Boolean OR operator returns TRUE (-1).
Boolean OR has an assignment form, OR=, that uses the variable to its left as both the first
operand and the result destination. For example,
Here, the value of X is promoted to TRUE if it is non-zero, then is compared with Y (also
promoted to TRUE if non-zero) and the Boolean result (TRUE / FALSE, -1 / 0) is stored back in X.
The assignment form of Boolean OR may also be used within expressions for intermediate
results; see Intermediate Assignments, page 253.
Be careful not to get Boolean OR ‘OR’ confused with Bitwise OR‘|’. Boolean OR is for
comparison purposes while Bitwise OR is for bit manipulation (see page 270).
The above example returns the Boolean opposite of Y; TRUE (-1) if Y is zero, or FALSE (0) if Y
is non-zero. During the comparison, it promotes the value of Y to -1 if it is non-zero, making
any value, other than 0, a -1, so that the comparison becomes: “If NOT true” or “If NOT
false”
Quite often this operator is used in combination with other comparison operators, such as in
the following example.
IF NOT ( (Y > 9) AND (Y < 21) )
This example evaluates the result of (Y > 9 AND Y < 21), and returns the Boolean opposite of
the result; TRUE (-1) if Y is in the range 10 to 20, in this case.
Boolean NOT becomes an assignment operator when it is the sole operator to the left of a
variable on a line by itself. For example:
NOT Flag
This would store the Boolean opposite of Flag back into Flag.
Be careful not to get Boolean NOT ‘NOT’ confused with Bitwise NOT‘!’. Boolean NOT is
for comparison purposes while Bitwise NOT is for bit manipulation (see page 272).
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if Y is the same value as Z, or FALSE (0) if Y is not the same value as Z.
This operator is often used in conditional expressions, such as in the following example.
IF (Y == 1)
Here, X is compared with Y, and if they are equal, X is set to TRUE (-1), otherwise X is set to
FALSE (0). The assignment form of Is Equal may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if Y is not the same value as Z, or FALSE (0) if Y is the same value as Z.
This operator is often used in conditional expressions, such as in the following example.
IF (Y <> 25)
Here, X is compared with Y, and if they are not equal, X is set to TRUE (-1), otherwise X is set to
FALSE (0). The assignment form of Is Not Equal may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if Y is less than the value of Z, or FALSE (0) if Y is equal to or greater than the value of Z.
This operator is often used in conditional expressions, such as in the following example.
IF (Y < 32)
Here, the Is Less Than operator returns TRUE if Y is less than 32.
Is Less Than has an assignment form, <=, that uses the variable to its left as both the first
operand and the result destination. For example,
X <= Y 'Short form of X := X < Y
Here, X is compared with Y, and if X is less than Y, X is set to TRUE (-1), otherwise X is set to
FALSE (0). The assignment form of Is Less Than may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if Y is greater than the value of Z, or FALSE (0) if Y is equal to or less than the value of Z.
This operator is often used in conditional expressions, such as in the following example.
Here, the Is Greater Than operator returns TRUE if Y is greater than 50.
Is Greater Than has an assignment form, >=, that uses the variable to its left as both the first
operand and the result destination. For example,
X >= Y 'Short form of X := X > Y
Here, X is compared with Y, and if X is greater than Y, X is set to TRUE (-1), otherwise X is set to
FALSE (0). The assignment form of Is Greater Than may also be used within expressions for
intermediate results; see Intermediate Assignments, page 253.
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if Y is equal to or less than the value of Z, or FALSE (0) if Y is greater than the value of Z.
This operator is often used in conditional expressions, such as in the following example.
IF (Y =< 75)
Here, the Is Equal or Less operator returns TRUE if Y is equal to or less than 75.
Is Equal or Less has an assignment form, =<=, that uses the variable to its left as both the first
operand and the result destination. For example,
X =<= Y 'Short form of X := X =< Y
Here, X is compared with Y, and if X is equal to or less than Y, X is set to TRUE (-1), otherwise X
is set to FALSE (0). The assignment form of Is Equal or Less may also be used within
expressions for intermediate results; see Intermediate Assignments, page 253.
The above example compares the value of Y with the value of Z and sets X to either: TRUE (-1)
if Y is equal to or greater than the value of Z, or FALSE (0) if Y is less than the value of Z.
This operator is often used in conditional expressions, such as in the following example.
IF (Y => 100)
Here, the Is Equal or Greater operator returns TRUE if Y is equal to or greater than 100.
Is Equal or Greater has an assignment form, =>=, that uses the variable to its left as both the
first operand and the result destination. For example,
X =>= Y 'Short form of X := X => Y
Here, X is compared with Y, and if X is equal to or greater than Y, X is set to TRUE (-1),
otherwise X is set to FALSE (0). The assignment form of Is Equal or Greater may also be used
within expressions for intermediate results; see Intermediate Assignments, page 253.
In the above example, the Symbol Address operator returns the address of the Str symbol,
which is then used by the BYTE memory array reference to store the character "A" at that
address.
Symbol Address is often used to pass the address of strings and data structures, defined in a
DAT block, to methods that operate on them.
It is important to note that this is a special operator that behaves differently in variable
expressions than it does in constant expressions. At run time, like our example above shows,
it returns the absolute address of the symbol following it. This run-time, absolute address
consists of the object’s program base address plus the symbol’s offset address.
In constant expressions, it only returns the symbol’s offset within the object. It can not return
the absolute address, effective at run time, because that address changes depending on the
object’s actual address at run time. To properly use the Symbol Address in a constant, such
as a table of data, see the Object Address Plus Symbol operator, below.
At run time we can access those strings directly, using @Str1, @Str2, and @Str3, but accessing
them indirectly is troublesome because each string is of a different length; making it difficult
to use any of them as a base for indirect address calculations.
The solution might seem to be within reach by simply making another table of the addresses
themselves, as in:
DAT
StrAddr word @Str1, @Str2, @Str3
This creates a table of words, starting at StrAddr, where each word contains the address of a
unique string. Unfortunately, for compile-time constants (like those of the StrAddr table), the
address returned by @ is only the compile-time offset address, rather than the run-time
absolute address, of the symbol. To get the true, run-time address, we need to add the
object’s program base address to the symbol’s offset address. That is what the Object
Address Plus Symbol operator does. Example:
REPEAT Idx FROM 0 TO 2
PrintStr(@@StrAddr[Idx])
The above example increments Idx from 0 through 2. The StrAddr[Idx] statement retrieves
the compile-time offset of the string stored in element Idx of the StrAddr table. The @@
operator in front of the StrAddr[Idx] statement adds the object’s base address to the
compile-time offset value that was retrieved, resulting in a valid run-time address of the
string. The PrintStr method, whose code is not shown in this example, can use that address
to process each character of the string.
((PUB ┆ PRI))
OUTA 〈[Pin(s)]〉
((PUB ┆ PRI))
OUTB 〈[Pin(s)]〉 (Reserved for future use)
Returns: Current value of output Pin(s) for Port A or B, if used as a source variable.
Explanation
OUTA and OUTB are two of six registers (DIRA, DIRB, INA, INB, OUTA and OUTB) that directly affect
the I/O pins. The OUTA register holds the output states for each of the 32 I/O pins in Port A;
bits 0 through 31 correspond to P0 through P31. The OUTB register holds the output states for
each of the 32 I/O pins in Port B; bits 0 through 31 correspond to P32 through P63.
NOTE: OUTB is reserved for future use; the Propeller P8X32A does not include Port B I/O
pins so only OUTA is discussed below.
OUTA is used to both set and get the current output states of one or more I/O pins in Port A. A
low (0) bit sets the corresponding I/O pin to ground. A high (1) bit sets the corresponding I/O
pin VDD (3.3 volts). The OUTA register defaults zero, all 0 bits, upon cog startup.
Each cog has access to all I/O pins at any given time. Essentially, all I/O pins are directly
connected to each cog so that there is no hub-related mutually-exclusive access involved.
Each cog maintains its own OUTA register that gives it the ability to set any I/O pin’s output
state (low or high). Each cog’s output states is OR’d with that of the other cogs’ output states
and the resulting 32-bit value becomes the output states of Port A pins P0 through P31. The
result is that each I/O pin’s output state is the “wired-OR” of the entire cog collective. See
I/O Pins on page 26 for more information.
Using OUTA
Set or clear bits in OUTA to affect the output state of I/O pins as desired. Make sure to also set
the corresponding bits of DIRA to make that pin an output. For example:
DIRA := %00000100_00110000_00000001_11110000
OUTA := %01000100_00110000_00000001_10010000
The DIRA line above sets the I/O pins 25, 21, 20, 8, 7, 6, 5 and 4 to outputs and the rest to
inputs. The OUTA line sets I/O pins 30, 25, 21, 20, 8, 7, and 4 to high, the rest to low. The
result is that I/O pins 25, 21, 20, 8, 7, and 4 output high and I/O pins 6 and 5 output low. I/O
pin 30 is set to an input direction (according to DIRA) so the high in bit 30 of OUTA is ignored
and the pin remains an input according to this cog.
Using the optional Pin(s) field, and the post-clear (~) and post-set (~~) unary operators, the
cog can affect one I/O pin (one bit) at a time. The Pin(s) field treats the I/O pin registers as
an array of 32 bits. For example:
DIRA[10]~~ 'Set P10 to output
OUTA[10]~ 'Make P10 low
OUTA[10]~~ 'Make P10 high
The first line, “DIRA…,” sets P12, P11, P10, P9 and P8 to outputs; all other pins remain in
their previous state. The second line, “OUTA…,” sets P12, P11, and P8 to output high, and P10
and P9 to output low.
IMPORTANT: The order of the values in a range-expression affects how it is used. For
example, the following swaps the order of the range from the previous example.
DIRA[8..12]~~ 'Set DIRA8:12 (P8-P12 to output)
OUTA[8..12] := %11001 'Set OUTA8:12 to 1, 1, 0, 0, and 1
Here, DIRA bits 8 through 12 are set to high (like before) but OUTA bits 8, 9, 10, 11 and 12 are
set equal to 1, 1, 0, 0, and 1, respectively, making P8, P9 and P12 output high and P10 and
P11 output low.
This is a powerful feature of range-expressions, but if care is not taken it can also cause
strange, unintentional results.
Normally OUTA is only written to but it can also be read from to retrieve the current I/O pin
output latch states. This is ONLY the cog’s output latch states, not necessarily the actual
output states of the Propeller chip’s I/O pins, as they can be further affected by other cogs or
even this cog’s other I/O hardware (Video Generator, Count A, etc.). The following assumes
Temp is a variable created elsewhere:
Temp := OUTA[15..13] 'Get output latch state of P15 to P13
The above sets Temp equal to OUTA bits 15, 14, and 13; i.e.: the lower 3 bits of Temp are now
equal to OUTA15:13 and the other bits of Temp are cleared to zero.
PAR
Cog Boot Parameter register.
((PUB ┆ PRI))
PAR
Returns: Address value passed during boot-up with COGINIT or COGNEW.
Explanation
The PAR register contains the address value passed into the Parameter field of a COGINIT or
COGNEW command; see COGINIT, page 187 and COGNEW, page 189. The PAR register’s contents
are used by Propeller Assembly code to locate and operate on memory shared between Spin
code and assembly code.
Since the PAR register is intended to contain an address upon cog boot-up, the value stored
into it via COGINIT and COGNEW is limited to 14-bits; a 16-bit word with lower two bits cleared
to zero.
Using PAR
PAR is affected by Spin code and is used by assembly code as a memory pointer mechanism to
point to shared main memory between the two. Either the COGINIT or COGNEW command, when
launching Propeller Assembly into a cog, affects the PAR register. For example:
VAR
long Shared 'Shared variable (Spin & Assy)
DAT
org 0
Process mov Mem, PAR 'Retrieve shared memory addr
:loop <do something>
wrlong ValReg, Mem 'Move ValReg value to Shared
jmp :loop
jmp :loop
In the example above, the Main method launches the Process assembly routine into a new cog
with COGNEW. The second parameter of COGNEW is used by Main to pass the address of a
variable, Shared. The assembly routine, Process, retrieves that address value from its PAR
register and stores it locally in Mem. Then it performs some task, updating its local ValReg
register (created at the end of the DAT block) and finally updates the Shared variable via
wrlong ValReg, Mem.
PHSA, PHSB
Counter A and Counter B Phase-Locked Loop (PLL) Registers.
((PUB ┆ PRI))
PHSA
((PUB ┆ PRI))
PHSB
Returns: Current value of Counter A or Counter B Phase Lock Loop Register, if used as a
source variable.
Explanation
PHSA and PHSB are two of six registers (CTRA, CTRB, FRQA, FRQB, PHSA, and PHSB) that affect the
behavior of a cog’s Counter Modules. Each cog has two identical counter modules (A and B)
that can perform many repetitive tasks. The PHSA and PHSB registers contain values that can
be directly read or written by the cog, but may also be accumulating with the value of FRQA
and FRQB, respectively, on potentially every System Clock cycle. See CTRA on page 204 for
more information.
The above code sets PHSA to $1FFFFFFF. Depending on the CTRMODE field of the CTRA
register, this value may remain the same, or may automatically increment by the value in FRQA
at a frequency determined by the System Clock and the primary and/or secondary I/O pins.
See CTRA, CTRB on page 204 for more information.
Keep in mind that writing to PHSA or PHSB directly overrides both the current accumulated
value and any potential accumulation scheduled for the same moment the write is performed.
((PUB ┆ PRI))
PRI Name 〈(Param 〈, Param〉…)〉 〈:RValue〉 〈| LocalVar 〈[Count]〉〉 〈,LocalVar 〈[Count]〉〉…
SourceCodeStatements
Explanation
PRI is the Private Method Block declaration. A Private Method is a section of source code
that performs a specific function then returns a result value. This is one of six special
declarations (CON, VAR, OBJ, PUB, PRI, and DAT) that provide inherent structure to the Spin
language.
Every object can contain a number of private (PRI) and public (PUB) methods. Private
methods can only be accessed from inside of the object and serve to perform vital, protected
functions, for the object. Private methods are like Public methods in every way except that
they are declared with PRI, instead of PUB, and are not accessible from outside the object.
Please see PUB, Page 287, for more information.
Page 286 · Propeller Manual v1.0
4: Spin Language Reference – PUB
PUB
Declare a Public Method Block.
((PUB ┆ PRI))
PUB Name 〈(Param 〈,Param〉…)〉 〈:RValue〉 〈| LocalVar 〈[Count ]〉〉 〈,LocalVar 〈[Count ]〉〉…
SourceCodeStatements
Explanation
PUB is the Public Method Block declaration. A Public Method is a section of source code that
performs a specific function then returns a result value. This is one of six special declarations
(CON, VAR, OBJ, PUB, PRI, and DAT) that provide inherent structure to the Spin language.
Every object can contain a number of public (PUB) and private (PRI) methods. Public methods
can be accessed outside of the object itself and serve to make up the interface to the object.
The PUB and PRI declarations don’t return a value themselves, but the public and private
methods they represent always return a value when called from elsewhere in the code.
This example contains three public methods, Init, MotorPos and MoveMotor. The Init
method has no parameters and declares no return value or local variables. The MotorPos
method has no parameters but declares a return value called Position. The MoveMotor
method has two parameters, Position and Speed, a return value, Success, and a local variable,
PosIndex.
All executable statements that belong to a PUB method appear underneath its declaration,
indented by at least one space.
When the MoveMotor method is executed, it receives the value of Pos in its Position
parameter, and the value 100 in its Speed parameter. Inside the MoveMotor method, it can
change Position and Speed at any time, but the value of Pos (the caller’s variable) remains at
250.
If a variable must be altered by a routine, the caller must pass the variable by reference;
meaning it must pass the address of the variable instead of the value of the variable, and the
routine must treat that parameter as the address of a memory location in which to operate on.
The address of a variable, or other register-based symbol, can be retrieved by using the
Symbol Address operator, ‘@’. For example,
Pos := 250
MoveMotor(@Pos, 100)
The caller passed the address of Pos for the first parameter to MoveMotor. What MoveMotor
receives in its Position parameter is the address of the caller’s Pos variable. The address is
just a number, like any other, so the MoveMotor method must be designed to treat it as an
address, rather than a value. The MoveMotor method then must use something like:
PosIndex := LONG[Position]
...to retrieve the value of the caller’s Pos variable, and something like:
LONG[Position] := <some expression>
Exiting a Method
A method is exited either when execution reaches the last statement within the method or
when it reaches a RETURN or ABORT command. A method may have only one exit point (the
last executable statement), or may have many exit points (any number of RETURN or ABORT
commands in addition to the last executable statement). The RETURN and ABORT commands
can also be used to set the RESULT variable upon exit; see RETURN, page 301, and ABORT, page
161.
QUIT
Exit from REPEAT loop immediately.
((PUB ┆ PRI))
QUIT
Explanation
QUIT is one of two commands (NEXT and QUIT) that affect REPEAT loops. QUIT causes a REPEAT
loop to terminate immediately.
Using QUIT
QUIT is typically used as an exception case, in a conditional statement, in REPEAT loops to
terminate the loop prematurely. For example, assume that DoMore and SystemOkay are
methods created elsewhere that each return Boolean values:
repeat while DoMore 'Repeat while more to do
!outa[0] 'Toggle status light
<do something> 'Perform some task
if !SystemOkay
quit 'If system failure, exit
<more code here> 'Perform other tasks
The above code toggles a status light on P0 and performs other tasks while the DoMore method
returns TRUE. However, if the SystemOkay method returns FALSE part-way through the loop,
the IF statement executes the QUIT command which causes the loop to terminate immediately.
The QUIT command can only be used within a REPEAT loop; an error will occur otherwise.
((PUB ┆ PRI))
REBOOT
Explanation
This is a software controlled reset, but acts like just like a hardware reset via the RESn pin.
Use REBOOT if you want to reset the Propeller chip to its power-up state. All the same
hardware-based, power-up/reset delays, as well as the boot-up processes, are applied as if the
Propeller had been reset via the RESn pin or a power cycle.
REPEAT
Execute code block repetitively.
((PUB ┆ PRI))
REPEAT 〈Count〉
Statement(s)
((PUB ┆ PRI))
REPEAT Variable FROM Start TO Finish 〈STEP Delta〉
Statement(s)
((PUB ┆ PRI))
REPEAT (( UNTIL┆ WHILE )) Condition(s)
Statement(s)
((PUB ┆ PRI))
REPEAT
Statement(s)
((UNTIL┆ WHILE)) Condition(s)
Indention is Critical
IMPORTANT: Indention is critical. The Spin language relies on indention (of one space or
more) on lines following conditional commands to determine if they belong to that command
or not. To have the Propeller Tool indicate these logically grouped blocks of code on-screen,
you can press Ctrl + I to turn on block-group indicators. Pressing Ctrl + I again will disable
that feature. See Indenting and Outdenting, page 69, and Block-Group Indicators, page 74.
This code repeats the !outa[25] and waitcnt(2_000 + cnt) lines endlessly. Both lines are
indented from the REPEAT so they belong to the REPEAT loop.
Since Statement(s) is really an optional part of REPEAT, the REPEAT command by itself can be
used as an endless loop that does nothing but keep the cog active. This can be intentional, but
sometimes is unintentional due to improper indention. For example:
repeat 'Repeat endlessly
!outa[25] 'Toggle P25 <-- This is never run
The above example is erroneous; the last line is never executed because the REPEAT above it is
an endless loop that has no Statement(s); there is nothing indented immediately below it, so
the cog simply sits in an endless loop at the REPEAT line that does nothing but keep the cog
active and consuming power.
The above code toggles P25 ten times, then increments the value in RAM location $7000.
Like the previous example, the code above loops 10 times, but each time it adjusts the
variable Index. The first time through the loop, Index will be 0 (as indicated by the “from 0”)
and each upon each iteration afterwards Index will be 1 higher than the previous (as indicated
by the “to 9”): ..1, 2, 3…9. After the tenth iteration, Index will be incremented to 10 and the
loop will terminate, causing the next code following the REPEAT loop structure to execute, if
any exists. The code in the loop uses Index as an offset to affect memory,
byte[$7000][Index]++; in this case it is incrementing each of the byte-sized values in RAM
locations $7000 to $7009 by 1, one at a time.
The REPEAT command automatically determines whether the range suggested by Start and
Finish is increasing or decreasing. Since the above example used 0 to 9, the range is an
increasing range; adjusting Index by +1 every time. To get the count to go backwards,
simply reverse the Start and Finish values, as in:
repeat Index from 9 to 0 'Repeat 10 times
byte[$7000][Index]++ 'Increment RAM $7009 down through $7000
This example also loops 10 times, but counts with Index from 9 down to 0; adjusting Index
by -1 each time. The contents of the loop still increments the values in RAM, but from
locations $7009 down to $7000. After the tenth iteration, Index will equal -1.
The above example uses a nested loop. The outer loop (the first one) repeats 2 times. The
inner loop repeats with Index from S to F, which were previously set to 0 and 9, respectively.
The inner loop increments the values in RAM locations $7000 to $7009, in that order,
because the inner loop is counting iterations from 0 to 9. Then, the inner loop terminates
(with Index being set to 10) and the last two lines set S to 9 and F to 0, effectively swapping
the Start and Finish values. Since this is still inside the outer loop, the outer loop then
executes its contents again (for the second time) causing the inner loop to repeat with Index
from 9 down to 0. The inner loop increments the values in RAM locations $7009 to $7000,
in that order (reverse of the previous time) and terminates with Index equaling -1. The last
two lines set S and F again, but the outer loop does not repeat a third time.
REPEAT loops don’t have to be limited to incrementing or decrementing by 1 either. If the
REPEAT command uses the optional STEP Delta syntax, it will increment or decrement the
Variable by the Delta amount. In the syntax 2 form, REPEAT is actually always using a Delta
value, but when the “STEP Delta” component is omitted, it uses either +1 or -1 by default,
depending on the range of Start and Finish. The following example includes the optional
Delta value to increment by 2.
repeat Index from 0 to 8 step 2 'Repeat 5 times
byte[$7000][Index]++ 'Increment even RAM $7000 to $7008
Here, REPEAT loops five times, with Index set to 0, 2, 4, 6, and 8, respectively. This code
effectively increments every other RAM location (the even numbered locations) from $7000
to $7008 and terminates with Index equaling 10.
The Delta field can be positive or negative, regardless of the natural ascending/descending
range of the Start and Finish values, and can even be adjusted within the loop to achieve
interesting effects. For example, assuming Index and D are previously defined variables, the
following code sets Index to the following sequence: 5, 6, 6, 5, 3.
This loop started out with Index at 5 and a Delta (D) of +2. But each iteration of the loop
decrements D by one, so at the end of iteration 1, Index = 5 and D = +1. Iteration 2 has Index
= 6 and D = 0. Iteration 3 has Index = 6 and D = -1. Iteration 4 has Index = 5 and D = -2.
Iteration 5 has Index = 3 and D = -3. The loop then terminates because Index plus Delta (3 + -
3) is outside the range of Start to Finish (5 to 10).
This example first sets X to 0, then repeats the loop while X is less than 10. The code inside
the loop clears RAM locations based on X (starting at location $7000) and increments X.
After the 10th iteration of the loop, X equals 10, making the condition while X < 10 false and
the loop terminates.
This loop is said to use “positive” logic because it continues “WHILE” a condition is true. It
could also be written with “negative” logic using UNTIL, instead. Such as:
X := 0
repeat until X > 9 'Repeat until X is greater than 9
byte[$7000][X] := 0 'Increment RAM value
X++ 'Increment X
This works the same as the previous examples, looping 10 times, except that the condition is
not tested until the end of each iteration. However, unlike the previous examples, even if X
was equal to 10 or higher before the first iteration, the loop would run once then terminate,
which is why we call it a one-to-many loop.
RESULT
The return value variable for methods.
((PUB ┆ PRI))
RESULT
Explanation
The RESULT variable is a pre-defined local variable for each PUB and PRI method. RESULT
holds the method’s return value; the value passed back to the caller of the method, when the
method is terminated.
When a public or private method is called, its built-in RESULT variable is cleared to zero (0).
If that method does not alter RESULT, or does not call RETURN or ABORT with a value specified,
then zero will be the return value upon that method’s termination.
Using RESULT
In the example below, the DoSomething method sets RESULT equal to 100 at its end. The Main
method calls DoSomething and sets its local variable, Temp, equal to the result; so that when
DoSomething exits, Temp will be set to 100
PUB Main | Temp
Temp := DoSomething 'Call DoSomething, set Temp to return value
PUB DoSomething
<do something here>
result := 100 'Set result to 100
You can also provide an alias name for a method’s RESULT variable in order to make it more
clear what the method returns. This is highly recommended since it makes a method’s intent
more easily discerned. For example:
PUB GetChar : Char
<do something>
Char := <retrieved character> 'Set Char (result) to the character
The above method, GetChar, declares Char as an alias for its built-in RESULT variable; see PUB,
page 287 or PRI, page 286, for more information. The GetChar method then performs some
task to get a character then it sets Char to the value of the retrieved character. It could have
RETURN
Exit from PUB/PRI method with optional return Value.
((PUB ┆ PRI))
RETURN 〈Value〉
Returns: Either the current RESULT value, or Value if provided.
• Value is an optional expression whose value is to be returned from the PUB or PRI
method.
Explanation
RETURN is one of two commands (ABORT and RETURN) that terminate a PUB or PRI method’s
execution. RETURN causes a return from a PUB or PRI method with normal status; meaning it
pops the call stack once and returns to the caller of this method, delivering a value in the
process.
Every PUB or PRI method has an implied RETURN at its end, but RETURN can also be manually
entered in one or more places within the method to create multiple exit points.
When RETURN appears without the optional Value, it returns the current value of the PUB/PRI’s
built-in RESULT variable. If the Value field was entered, however, the PUB or PRI returns with
that Value instead.
The Add method sets its built-in RESULT variable equal to Num1 plus Num2, then executes
RETURN. The RETURN causes Add to return the value of RESULT to the caller. Note that this
RETURN was not really required because the Propeller Tool Compiler will automatically put it
in at the end of any methods that don’t have one.
The Divide method checks the Divisor value. If Divisor equals zero, it calls a
DisplayDivByZeroError method and then executes return 0, which immediately causes the
method to return with the value 0. If, however, the Divisor was not equal to zero, it executes
return Dividend / Divisor, which causes the method to return with the result of the
division. This is an example where the last RETURN was used to perform the calculation and
return the result all in one step rather than separately affecting the built-in RESULT variable
beforehand.
ROUND
Round a floating-point constant to the nearest integer.
Explanation
ROUND is one of three directives (FLOAT, ROUND and TRUNC) used for floating-point constant
expressions. ROUND returns an integer constant that is the closest integer value to the given
floating-point constant expression. Fractional values of ½ (.5) or higher are rounded up to the
nearest whole number while lower fractions are rounded down.
Using ROUND
ROUND can be used to round floating-point constants up or down to the nearest integer value.
Note that this is for compile-time constant expressions only, not run-time variable
expressions. For example:
CON
OneHalf = 0.5
Smaller = 0.4999
Rnd1 = round(OneHalf)
Rnd2 = round(Smaller)
Rnd3 = round(Smaller * 10.0) + 4
The above code creates two floating-point constants, OneHalf and Smaller, equal to 0.5 and
0.4999, respectively. The next three constants, Rnd1, Rnd2 and Rnd3, are integer constants
that are based on OneHalf and Smaller using the ROUND directive. Rnd1 = 1, Rnd2 = 0, and
Rnd3 = 9.
SPR
Special Purpose Register array; provides indirect access to cog’s special registers.
((PUB ┆ PRI))
SPR [Index]
Returns: Value in special purpose register at Index.
• Index is an expression that specifies the index (0-15) of the special purpose register to
access (PAR through VSCL).
Explanation
SPRis an array of the 16 special purpose registers in the cog. Element 0 is the PAR register and
element 15 is the VSCL register. See Table 4-15 below. SPR provides an indirect method of
accessing the cog’s special purpose registers.
This example sets the OUTA register (index 4 of SPR) to %11001010 and then sets Temp equal to
the INA register (index 2 of SPR).
_STACK
Pre-defined, one-time settable constant for specifying the size of an application’s stack space.
CON
_STACK = Expression
• Expression is an integer expression that indicates the number of longs to reserve for
stack space.
Explanation
_STACK is a pre-defined, one-time settable optional constant that specifies the required stack
space of an application. This value is added to _FREE if specified, to determine the total
amount of stack/free memory space to reserve for a Propeller application. Use _STACK if an
application requires a minimum amount of stack space in order to run properly. If the
resulting compiled application is too large to allow the specified stack space, an error
message will be displayed. For example:
CON
_STACK = 3000
The _STACK declaration in the above CON block indicates that the application needs to have at
least 3,000 longs of stack space left over after compilation. If the resulting compiled
application does not have that much room left over, an error message will indicate by how
much it was exceeded. This is a good way to prevent successful compiles of an application
that will fail to run properly due to lack of memory.
Note that only the top object file can set the value of _STACK. Any child object’s _STACK
declarations will be ignored. The stack space reserved by this constant is used by the
application’s main cog to store temporary data such as call stacks, parameters, and
intermediate expression results.
((PUB ┆ PRI))
STRCOMP (StringAddress1, StringAddress2 )
Returns: TRUE if both strings are equal, FALSE otherwise.
Explanation
STRCOMP is one of two commands (STRCOMP and STRSIZE) that retrieve information about a
string. STRCOMP compares the contents of the string at StringAddress1 to the contents of the
string at StringAddress2, up to the zero-terminator of each string, and returns TRUE if both
strings are equivalent, FALSE otherwise. This comparison is case-sensitive.
Using STRCOMP
The following example assumes PrintStr is a method created elsewhere.
PUB Main
if strcomp(@Str1, @Str2)
PrintStr(string("Str1 and Str2 are equal"))
else
PrintStr(string("Str1 and Str2 are different"))
DAT
Str1 byte "Hello World", 0
Str2 byte "Testing.", 0
The above example has two zero-terminated strings in the DAT block, Str1 and Str2. The
Main method calls STRCOMP to compare the contents of each string. Assuming PrintStr is a
method that displays a string, this example prints “Str1 and Str2 are different” on the display.
((PUB ┆ PRI))
STRING (StringExpression )
Returns: Address of in-line string constant.
Explanation
The DAT block is used often to create strings or string buffers that are reusable for various
purposes, but there are occasions when a string is needed for temporary purposes like
debugging or one-time uses in an object. The STRING directive is meant for those one-time
uses; it compiles an in-line, zero-terminated string into memory and returns the address of
that string.
Using STRING
The STRING directive is very good for creating one-time-use strings and passing the address of
that string to other methods. For example, assuming PrintStr is a method created elsewhere.
PrintStr(string("This is a test string."))
The above example uses the STRING directive to compile a string, “This is a test string.”, into
memory and return the address of that string as the parameter for the fictitious PrintStr
method.
If a string needs to be used in more than one place in code, it is better to define it in the DAT
block so the address can be used multiple times.
STRSIZE
Get size of string.
((PUB ┆ PRI))
STRSIZE ( StringAddress )
Returns: Size (in bytes) of zero-terminated string.
Explanation
STRSIZE is one of two commands (STRCOMP and STRSIZE) that retrieve information about a
string. STRSIZE measures the length of a string at StringAddress, in bytes, up to, but not
including, a zero-termination byte.
Using STRSIZE
The following example assumes Print is a method created elsewhere.
PUB Main
Print(strsize(@Str1))
Print(strsize(@Str2))
DAT
Str1 byte "Hello World", 0
Str2 byte "Testing.", 0
The above example has two zero-terminated strings in the DAT block, Str1 and Str2. The
Main method calls STRSIZE to get the length of each string. Assuming Print is a method that
displays a value, this example prints 11 and 8 on the display.
Zero-Terminated Strings
The STRSIZE command requires the string being measured to be zero-terminated; a byte equal
to 0 must immediately follow the string. This practice is quite common and is recommended
since most string-handling methods rely on zero terminators.
Symbols
The symbols in Table 4-16 below serve one or more special purposes in Spin code. Each
symbol’s purpose is described briefly with references to other sections that describe it directly
or use it in examples.
Using TRUNC
TRUNC can be used to retrieve the integer portion of a floating-point constant. For example:
CON
OneHalf = 0.5
Bigger = 1.4999
Int1 = trunc(OneHalf)
Int2 = trunc(Bigger)
Int3 = trunc(Bigger * 10.0) + 4
The above code creates two floating-point constants, OneHalf and Bigger, equal to 0.5 and
1.4999, respectively. The next three constants, Int1, Int2 and Int3, are integer constants that
are based on OneHalf and Bigger using the TRUNC directive. Int1 = 0, Int2 = 1, and Int3 = 18.
VAR
Declare a Variable Block.
VAR
Size Symbol 〈[Count ]〉 〈 Size Symbol 〈 [Count ]〉〉...
VAR
Size Symbol 〈[Count ]〉 〈 , Symbol 〈 [Count ]〉〉...
Explanation
VAR is the Variable Block declaration. The Variable Block is a section of source code that
declares global variable symbols. This is one of six special declarations (CON, VAR, OBJ, PUB,
PRI, and DAT) that provide inherent structure to the Spin language.
This example defines Str as a byte array of 10 elements, Code as a word (two bytes) and
LargeNumber as a long (four bytes). Public and Private methods can refer to these variables in
ways similar to the following:
Notice that Code and LargeNumber are used directly by expressions. The Str reference in the
GetString method’s parameter list looks different; it has an @, the Symbol Address operator,
preceding it. This is because our fictitious GetString method needs to write back to the Str
variable. If we had said GetString(Str), then the first byte of Str, element 0, would have
been passed to GetString. By using the Symbol Address operator, @, we caused the address of
Str to be passed to GetString instead; GetString can use that address to write to Str’s
elements. Lastly, we use Str[0] in the condition of an IF statement to see if the first byte is
equal to the character "A". Remember, the first element of an array is always zero (0).
Scope of Variables
Symbolic variables defined in Variable Blocks are global to the object in which they are
defined but not outside of that object. This means that these variables can be accessed
directly from anywhere within the object but their name will not conflict with symbols
defined in other parent or child objects.
Public and Private methods have the ability to declare their own local variables. See PUB,
page 287, and PRI, page 286.
Global variables are not accessible outside of an object unless the address of that variable is
passed into, or back to, another object through a method call.
VCFG
Video Configuration Register.
((PUB ┆ PRI))
VCFG
Returns: Current value of cog’s Video Configuration Register, if used as a source variable.
Explanation
VCFG is one of two registers (VCFG and VSCL) that affect the behavior of a cog’s Video
Generator. Each cog has a video generator module that facilitates transmitting video image
data at a constant rate. The VCFG register contains the configuration settings of the video
generator, as shown in Table 4-17.
In Propeller Assembly, the VMode field through AuralSub fields can conveniently be written
using the MOVI instruction, the VGroup field can be written with the MOVD instruction, and the
VPins field can be written with the MOVS instruction.
VMode
The 2-bit VMode (video mode) field selects the type and orientation of video output, if any,
according to Table 4-18.
Chroma1
The Chroma1 (broadcast chroma) bit enables or disables chroma (color) on the broadcast
signal. 0 = disabled, 1 = enabled.
Chroma0
The Chroma0 (baseband chroma) bit enables or disables chroma (color) on the baseband
signal. 0 = disabled, 1 = enabled.
AuralSub
The AuralSub (aural sub-carrier) field selects the source of the FM aural (audio) sub-carrier
frequency to be modulated on. The source is the PLLA of one of the cogs, identified by
AuralSub’s value.
VPins
The VPins (video output pins) field is a mask applied to the pins of VGroup that indicates
which pins to output video signals on.
Using VCFG
VCFG can be read/written like other registers or pre-defined variables. For example:
VCFG := %0_10_1_0_1_000_00000000000_001_0_00001111
This sets the video configuration register to enable video in composite mode 1 with 4 colors,
baseband chroma (color) enabled, on pin group 1, lower 4 pins (which is pins P11:8).
((PUB ┆ PRI))
VSCL
Returns: Current value of cog’s Video Scale Register, if used as a source variable.
Explanation
VSCL is one of two registers (VCFG and VSCL) that affect the behavior of a cog’s Video
Generator. Each cog has a video generator module that facilitates transmitting video image
data at a constant rate. The VSCL register sets the rate at which video data is generated.
PixelClocks
The 8-bit PixelClocks field indicates the number of clocks per pixel; the number of clocks
that should elapse before each pixel is shifted out by the video generator module. These
clocks are the PLLA clocks, not the System Clock.
FrameClocks
The 12-bit FrameClocks field indicates the number of clocks per frame; the number of clocks
that should elapse before each frame is shifted out by the video generator module. These
clocks are the PLLA clocks, not the System Clock. A frame is one long of pixel data
(delivered via the WAITVID command). Since the pixel data is either 16 bits by 2 bits, or 32
bits by 1 bit (meaning 16 pixels wide with 4 colors, or 32 pixels wide with 2 colors,
respectively), the FrameClocks is typically 16 or 32 times that of the PixelClocks value.
Using VSCL
VSCL can be read/written like other registers or pre-defined variables. For example:
VSCL := %000000000000_10100000_101000000000
((PUB ┆ PRI))
WAITCNT ( Value )
Explanation
WAITCNT, “Wait for System Counter,” is one of four wait commands (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. WAITCNT
pauses the cog until the global System Counter equals Value.
When executed, WAITCNT activates special “wait” hardware in the cog that prevents the
System Clock from causing further code execution within the cog until the moment the
System Counter equals Value. The wait hardware checks the System Counter every System
Clock cycle and the cog’s power consumption is reduced by approximately 7/8ths during this
time. In normal applications, WAITCNT may be used strategically to reduce power
consumption anywhere in the program where time is wasted waiting for low-bandwidth
events.
There are two types of delays WAITCNT can be used for: fixed delays and synchronized delays.
Both are explained below.
Fixed Delays
Fixed delays are those that are all unrelated to one specific point in time and only serve the
purpose of pausing execution for a fixed amount of time. A fixed delay, for example, may be
used to wait for 10 milliseconds after an event occurs, before proceeding with another action.
For example:
CON
_clkfreq = xtal1 'Set for slow crystal
_xinfreq = 5_000_000 'Use 5 MHz accurate crystal
repeat
!outa[0] 'Toggle pin 0
waitcnt(50_000 + cnt) 'Wait for 10 ms
Synchronized Delays
Synchronized delays are those that are all directly related to one specific point in time, a
“base” time, and serve the purpose of “time-aligning” future events relative to that point. A
synchronized delay, for example, may be used to output or input a signal at a specific
interval, despite the unknown amounts of overhead associated with the code itself. To
understand how this is different than the Fixed Delay example, let’s look at that example’s
timing diagram.
Figure 4-1 shows the output of our previous example, the fixed delay example. Notice how
the I/O pin P0 toggles roughly every 10 milliseconds, but not exactly? In fact, there’s a
cumulative error that makes successive state changes further and further out-of-sync in
relation to our start time, 0 ms. The delay is 10 ms in length, but the error occurs because that
delay doesn’t compensate for the length of the rest of the loop. The repeat, !outa[0] and
WAITCNT statements each take a little time to execute, and all that extra time is in addition to
the 10 ms delay that WAITCNT specified.
Using WAITCNT a slightly different way, for a synchronized delay, will eliminate this timing
error. The following example assumes we’re using a 5 MHz external crystal.
CON
_clkfreq = xtal1 'Set for slow crystal
_xinfreq = 5_000_000 'Use 5 MHz accurate crystal
This code first retrieves the value of the System Counter, Time := cnt, then starts the repeat
loop where it waits for the System Counter to reach Time + 50,000, toggles the state of I/O
pin P0 and repeats the loop again. The statement Time += 50_000 is actually an assignment
statement; it adds the value of Time to 50,000, stores that result back into Time and then
executes the WAITCNT command using that result. Notice that we retrieved the System
Counter’s value only once, at the start of the example; that is our base time. Then we wait for
the System Counter to equal that original base time plus 50,000 and perform the actions in the
loop. Each successive iteration through the loop, we wait for the System Counter to equal
another multiple of 50,000 from the base time. This method automatically compensates for
Using the synchronized delay method, our output signal is always perfectly aligned to the
time base plus a multiple of our interval. This will work as long as the time base (an external
crystal) is accurate and the overhead in the loop does not exceed the time interval itself. Note
that we waited, with WAITCNT, before the first toggle so that the time between the very first
toggle and the second matches that of all the rest.
Calculating Time
An object can delay a specific amount of time even if the application changes the System
Clock frequency occasionally. To do this, use WAITCNT combined with an expression that
includes the current System Clock frequency (CLKFREQ). For example, without you knowing
what the actual clock frequency will be for applications using your object, the following line
can be used to delay the cog for 1 millisecond; as long as the clock frequency is fast enough.
waitcnt(clkfreq / 1000 + cnt) 'delay cog 1 millisecond
((PUB ┆ PRI))
WAITPEQ (State, Mask, Port )
• State is the logic state(s) to compare the pin(s) against. It is a 32-bit value that
indicates the high or low states of up to 32 I/O pins. State is compared against either
(INA & Mask), or (INB & Mask), depending on Port.
• Mask is the desired pin(s) to monitor. Mask is a 32-bit value that contains high (1)
bits for every I/O pin that should be monitored; low (0) bits indicate pins that should
be ignored. Mask is bitwised-ANDed with the 32-bit port’s input states and the
resulting value is compared against the entire State value.
• Port is a 1-bit value indicating the I/O port to monitor; 0 = Port A, 1 = Port B. Only
Port A exists on current (P8X32A) Propeller chips.
Explanation
WAITPEQ, “Wait for Pin(s) to Equal,” is one of four wait commands (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. WAITPEQ
pauses the cog until the value of Port’s I/O pin states, bitwised-ANDed with Mask, matches
that of State.
When executed, WAITPEQ activates special “wait” hardware in the cog that prevents the
System Clock from causing further code execution within the cog until the moment the
designated pin, or group of pins, equals the indicated state(s). The wait hardware checks the
I/O pins every System Clock cycle and the cog’s power consumption is reduced by
approximately 7/8ths during this time.
Using WAITPEQ
WAITPEQ is a great way to synchronize code to external events. For example:
waitpeq(%0100, %1100, 0) 'Wait for P3 & P2 to be low & high
outa[0] := 1 'Set P0 high
The above code pauses the cog until I/O pin 3 is low and I/O pin 2 is high, then sets I/O pin 0
high.
The Mask parameter, |< Pin, evaluates to a long value where only one bit is high; the bit that
corresponds to the pin number given by Pin.
This example first waits for P5 to go high, then waits for it to go low; a high-to-low
transition. If we had used the second line of code without the first, the cog would not have
paused at all if P5 had been low to start with.
((PUB ┆ PRI))
WAITPNE (State, Mask, Port )
• State is the logic state(s) to compare the pins against. It is a 32-bit value that
indicates the high or low states of up to 32 I/O pins. State is compared against either
(INA & Mask), or (INB & Mask), depending on Port.
• Mask is the desired pin(s) to monitor. Mask is a 32-bit value that contains high (1)
bits for every I/O pin that should be monitored; low (0) bits indicate pins that should
be ignored. Mask is bitwised-ANDed with the 32-bit port’s input states and the
resulting value is compared against the entire State value.
• Port is a 1-bit value indicating the I/O port to monitor; 0 = Port A, 1 = Port B. Only
Port A exists on current (P8X32A) Propeller chips.
Explanation
WAITPNE, “Wait for Pin(s) to Not Equal,” is one of four wait commands (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. WAITPNE is
the complimentary form of WAITPEQ; it pauses the cog until the value of Port’s I/O pin states,
bitwised-ANDed with Mask, does not match that of State.
When executed, WAITPNE activates special “wait” hardware in the cog that prevents the
System Clock from causing further code execution within the cog until the moment the
designated pin, or group of pins, does not equal the designated state(s). The wait hardware
checks the I/O pins every System Clock cycle and the cog’s power consumption is reduced
by approximately 7/8ths during this time.
Using WAITPNE
WAITPNE is a great way to synchronize code to external events. For example:
waitpeq(%0100, %1100, 0) 'Wait for P3 & P2 to be low & and high
waitpne(%0100, %1100, 0) 'Wait for P3 & P2 to not match prev. state
outa[0] := 1 'Set P0 high
The above code pauses the cog until P3 is low and P2 is high, then pauses the cog again until
one or both of those pins changes states, then it sets P0 high.
WAITVID
Pause a cog’s execution until its Video Generator is available to take pixel data.
((PUB ┆ PRI))
WAITVID (Colors, Pixels )
• Colors is a long containing four byte-sized color values, each describing the four
possible colors of the pixel patterns in Pixels.
• Pixels is the next 16-pixel by 2-bit (or 32-pixel by 1-bit) pixel pattern to display.
Explanation
WAITVID, “Wait for Video Generator,” is one of four wait commands (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. WAITVID
pauses the cog until its Video Generator hardware is ready for the next pixel data, then the
Video Generator accepts that data and the cog continues execution with the next line of code.
When executed, WAITVID activates special “wait” hardware in the cog that prevents the
System Clock from causing further code execution within the cog until the moment the Video
Generator is ready. The wait hardware checks the Video Generator’s status every System
Clock cycle and the cog’s power consumption is reduced significantly during this time.
Using WAITVID
WAITVID is simply a delivery mechanism for data to the cog’s Video Generator hardware.
Since the Video Generator works independently from the cog itself, the two must synchronize
each time data is needed for the display device. The frequency at which this occurs depends
on the display device and the corresponding settings for the Video Generator, but in every
case, the cog must have new data available the moment the Video Generator is ready for it.
The cog uses the WAITVID command to wait for the right time and then “hand off” this data to
the Video Generator.
The Colors parameter is a 32-bit value containing either four 8-bit color values (for 4-color
mode) or two 8-bit color values in the lower 16 bits (for 2-color mode). For VGA, each color
value’s upper 6-bits is the 2-bit red, 2-bit green, and 2-bit blue color components describing
the desired color; the lower 2-bits are “don’t care” bits. Each of the color values corresponds
to one of the four possible colors per 2-bit pixel (when Pixels is used as a 16x2 bit pixel
pattern) or as one of the two possible colors per 1-bit pixel (when Pixels is used at a 32x1 bit
pixel pattern).
WORD
Declare word-sized symbol, word aligned/sized data, or read/write a word of main memory.
VAR
WORD Symbol 〈[Count ]〉
DAT
WORD Data
((PUB ┆ PRI))
WORD [BaseAddress] 〈[Offset ]〉
((PUB ┆ PRI))
Symbol.WORD 〈[Offset ]〉
• Symbol is the desired name for the variable (Syntax 1) or the existing name of the
variable (Syntax 4).
• Count is an optional expression indicating the number of word-sized elements for
Symbol, arranged in an array from element 0 to element Count-1.
• Data is a constant expression or comma-separated list of constant expressions.
• BaseAddress is an expression describing the address of main memory to read or write.
If Offset is omitted, BaseAddress is the actual address to operate on. If Offset is
specified, BaseAddress + Offset is the actual address to operate on.
• Offset is an optional expression indicating the offset from BaseAddress to operate on,
or the offset from word 0 of Symbol.
Explanation
WORD is one of three multi-purpose declarations (BYTE, WORD, and LONG) that declare or operate
on memory. WORD can be used to:
1) declare a word-sized (16-bit) symbol or a multi-word symbolic array in a VAR block, or
2) declare word-aligned, and/or word-sized, data in a DAT block, or
3) read or write a word of main memory at a base address with an optional offset, or
4) access a word within a long-sized variable.
The above example declares two variables (symbols), Temp and List. Temp is simply a single,
word-sized variable. The line under the Temp declaration uses the optional Count field to
create an array of 25 word-sized variable elements called List. Both Temp and List can be
accessed from any PUB or PRI method within the same object that this VAR block was declared;
they are global to the object. An example of this is below.
PUB SomeMethod
Temp := 25_000 'Set Temp to 25,000
List[0] := 500 'Set first element of List to 500
List[1] := 9_000 'Set second element of List to 9,000
List[24] := 60_000 'Set last element of List to 60,000
For more information about using WORD in this way, refer to the VAR section’s Variable
Declarations (Syntax 1) on page 315, and keep in mind that WORD is used for the Size field in
that description.
The above example declares two data symbols, MyData and MyList. MyData points to the start
of word-aligned and word-sized data in main memory. MyData’s values, in main memory, are
640, $AAAA and 5,500, respectively. MyList uses a special DAT block syntax of WORD that
creates a byte-aligned but word-sized set of data in main memory. MyList’s values, in main
memory, are $FF99 and 1,000, respectively. When accessed a byte at a time, MyList contains
$99, $FF, 232 and 3 since the data is stored in little-endian format.
This data is compiled into the object and resulting application as part of the executable code
section and may be accessed using the read/write form, syntax 3, of WORD (see below). For
more information about using WORD in this way, refer to the DAT section’s Declaring Data
The first line inside of the GetData method, Temp := MyData, reads the first value in the
MyData list (the word-sized value 640) and stores it in Temp. Further down, in the REPEAT loop,
the Temp := MyList[Index] line reads a byte of main memory from the location of MyList +
Index. The first time through the loop (Index = 0) the value $99 ($FF99’s low-byte) is read
from MyList and the second time through the loop (Index = 1) the next byte is read, $FF
($FF99’s high-byte). Why were bytes read instead of words? MyList points at the start of our
desired data and our data was specified as word-sized data but the symbol MyList is treated as
a byte pointer since that data was specified to be byte-aligned.
Perhaps you intended to read word-sized data from MyList just like we did from MyData.
Coincidentally, even though MyList is declared as byte-aligned word data, it is also happens
to be word-aligned as well because the previous declaration finished on a word boundary.
This fact allows us to use the WORD declaration to achieve our goal.
PUB GetData | Index, Temp
Temp := WORD[@MyData] 'Read first word of MyData into Temp
<do something with Temp> 'Perform task with Temp
This line writes the value 8,192 to the first word of data at MyList.
PUB Main
LongVar.word := 65000 'Set first word of LongVar to 65000
LongVar.word[0] := 65000 'Same as above
LongVar.word[1] := 1 'Set second word of LongVar to 1
This example accesses the word-sized components of LongVar, individually. The comments
indicate what each line is doing. At the end of the Main method LongVar will equal 130,536.
WORDFILL
Fill words of main memory with a value.
((PUB ┆ PRI))
WORDFILL (StartAddress, Value, Count )
• StartAddress is an expression indicating the location of the first word of memory to fill
with Value.
• Value is an expression indicating the value to fill words with.
• Count is an expression indicating the number of words to fill, starting with
StartAddress.
Explanation
WORDFILL is one of three commands (BYTEFILL, WORDFILL, and LONGFILL) used to fill blocks of
main memory with a specific value. WORDFILL fills Count words of main memory with Value,
starting at location StartAddress.
Using WORDFILL
WORDFILL is a great way to clear large blocks of word-sized memory. For example:
VAR
word Buff[100]
PUB Main
wordfill(@Buff, 0, 100) 'Clear Buff to 0
The first line of the Main method, above, clears the entire 100-word (200-byte) Buff array to
all zeros. WORDFILL is faster at this task than a dedicated REPEAT loop is.
((PUB ┆ PRI))
WORDMOVE (DestAddress, SrcAddress, Count )
• DestAddress is an expression specifying the main memory location to copy the first
word of source to.
• SrcAddress is an expression specifying the main memory location of the first word of
source to copy.
• Count is an expression indicating the number of words of the source to copy to the
destination.
Explanation
WORDMOVE is one of three commands (BYTEMOVE, WORDMOVE, and LONGMOVE) used to copy blocks
of main memory from one area to another. WORDMOVE copies Count words of main memory
starting from SrcAddress to main memory starting at DestAddress.
Using WORDMOVE
WORDMOVE is a great way to copy large blocks of word-sized memory. For example:
VAR
word Buff1[100]
word Buff2[100]
PUB Main
wordmove(@Buff2, @Buff1, 100) 'Copy Buff1 to Buff2
The first line of the Main method, above, copies the entire 100-word (200-byte) Buff1 array to
the Buff2 array. WORDMOVE is faster at this task than a dedicated REPEAT loop.
_XINFREQ
Pre-defined, one-time settable constant for specifying the external crystal frequency.
CON
_XINFREQ = Expression
• Expression is an integer expression that indicates the external crystal frequency; the
frequency on the XI pin. This value is used for application start-up.
Explanation
_XINFREQ specifies the external crystal frequency, which is used along with the clock mode to
determine the System Clock frequency at start-up. It is a pre-defined constant symbol whose
value is determined by the top object file of an application. _XINFREQ is either set directly by
the application itself, or is set indirectly as the result of the _CLKMODE and _CLKFREQ settings.
The top object file in an application (the one where compilation starts from) can specify a
setting for _XINFREQ in its CON block. This, along with the clock mode, defines the frequency
that the System Clock will switch to as soon as the application is booted up and execution
begins.
The application can specify either _XINFREQ or _CLKFREQ in the CON block; they are mutually
exclusive and the non-specified one is automatically calculated and set as a result of
specifying the other.
The following examples assume that they are contained within the top object file. Any
_XINFREQ settings in child objects are simply ignored by the compiler.
For example:
CON
_CLKMODE = XTAL1 + PLL8X
_XINFREQ = 4_000_000
The first declaration in the above CON block sets the clock mode for an external low-speed
crystal and a Clock PLL multiplier of 8. The second declaration indicates the external crystal
frequency is 4 MHz, which means the System Clock’s frequency will be 32 MHz because 4
MHz * 8 = 32 MHz. The _CLKFREQ value is automatically set to 32 MHz because of these
declarations.
These two declarations set the clock mode for an external medium-speed crystal, no Clock
PLL multiplier, and an external crystal frequency of 10 MHz. The _CLKFREQ value, and thus
the System Clock frequency, is automatically set to 10 MHz, as well, because of these
declarations.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
{Launch cog to toggle P16 endlessly}
DAT
{Toggle P16}
ORG 0 'Begin at Cog RAM addr 0
Toggle mov dira, Pin 'Set Pin to output
mov Time, cnt 'Calculate delay time
add Time, #9 'Set minimum delay here
:loop waitcnt Time, Delay 'Wait
xor outa, Pin 'Toggle Pin
jmp #:loop 'Loop endlessly
Both assembly and data may be intermixed within the DAT block but care should be taken to
arrange it such that all critical elements are loaded into the cog in the proper order for
execution. The COGNEW and COGINIT commands, when used to launch Propeller Assembly
code, cause the cog to be loaded with 496 consecutive long values starting from the specified
address. Whether or not it is required by the code, any data intermixed with this 496 longs of
space will be loaded as well.
Each Propeller assembly instruction has common syntax elements consisting of an optional
label, optional condition, instruction, and optional effects. See Common Syntax Elements,
page 348, for more information.
Directives
ORG Adjust compile-time cog address pointer; p 392.
FIT Validate that previous instructions/data fit entirely in cog; p 372.
RES Reserve next long(s) for symbol; p 397.
Configuration
CLKSETs Set clock mode at run time; p 361.
Cog Control
COGIDs Get current cog’s ID; p 365.
COGINITs Start, or restart, a cog by ID; p 366.
COGSTOPs Stop a cog by ID; p 367.
Process Control
LOCKNEWs Check out a new lock; p 376.
LOCKRETs Return a lock; p 376.
LOCKCLRs Clear a lock by ID; p 375.
LOCKSETs Set a lock by ID; p 377.
WAITCNTs Pause execution temporarily; p 411.
WAITPEQs Pause execution until pin(s) match designated state(s); p 412.
WAITPNEs Pause execution until pin(s) do not match designated state(s); p 413.
WAITVIDs Pause execution until Video Generator is available for pixel data; p 414.
Conditions
IF_ALWAYS Always; p 369.
IF_NEVER Never; p 369.
IF_E If equal (Z = 1); p 369.
IF_NE If not equal (Z = 0); p 369.
IF_A If above (!C & !Z = 1); p 369.
Propeller Manual v1.0 · Page 341
Assembly Language Reference
IF_B If below (C = 1); p 369.
IF_AE If above or equal (C = 0); p 369.
IF_BE If below or equal (C | Z = 1); p 369.
IF_C If C set; p 369.
IF_NC If C clear; p 369.
IF_Z If Z set; p369.
IF_NZ If Z clear; p 369.
IF_C_EQ_Z If C equal to Z; p 369.
IF_C_NE_Z If C not equal to Z; p 369.
IF_C_AND_Z If C set and Z set; p 369.
IF_C_AND_NZ If C set and Z clear; p 369.
IF_NC_AND_Z If C clear and Z set; p 369.
IF_NC_AND_NZ If C clear and Z clear; p 369.
IF_C_OR_Z If C set or Z set; p 369.
IF_C_OR_NZ If C set or Z clear; p 369.
IF_NC_OR_Z If C clear or Z set; p 369.
IF_NC_OR_NZ If C clear or Z clear; p 369.
IF_Z_EQ_C If Z equal to C; p 369.
IF_Z_NE_C If Z not equal to C; p 369.
IF_Z_AND_C If Z set and C set; p 369.
IF_Z_AND_NC If Z set and C clear; p 369.
IF_NZ_AND_C If Z clear and C set; p 369.
IF_NZ_AND_NC If Z clear and C clear; p 369.
IF_Z_OR_C If Z set or C set; p 369.
IF_Z_OR_NC If Z set or C clear; p 369.
IF_NZ_OR_C If Z clear or C set; p 369.
IF_NZ_OR_NC If Z clear or C clear; p 369.
Flow Control
CALL Jump to address with intention to return to next instruction; p 360.
DJNZ Decrement value and jump to address if not zero; p 370.
JMP Jump to address unconditionally; p 374.
JMPRET Jump to address with intention to “return” to another address; p 374.
TJNZ Test value and jump to address if not zero; p 409.
TJZ Test value and jump to address if zero; p 410.
RET Return to stored address; p 399.
Effects
NR No result (don’t write result); p 371.
WR Write result; p 371.
WC Write C status; p 371.
WZ Write Z status; p 371.
Common Operations
ABS Get absolute value of a number; p 353.
ABSNEG Get negative of number’s absolute value; p 354.
NEG Get negative of a number; p 386.
NEGC Get a value, or its additive inverse, based on C; p 386.
NEGNC Get a value or its additive inverse, based on !C; p 387.
NEGZ Get a value, or its additive inverse, based on Z; p 389.
Registers
DIRAs Direction Register for 32-bit port A; p 397.
DIRBs Direction Register for 32-bit port B (future use); p 397.
INAs Input Register for 32-bit port A (read only); p 397.
INBs Input Register for 32-bit port B (read only) (future use); p 397.
OUTAs Output Register for 32-bit port A; p 397.
OUTBs Output Register for 32-bit port B (future use); p 397.
CNTs 32-bit System Counter Register (read only); p 397.
CTRAs Counter A Control Register; p 397.
CTRBs Counter B Control Register; p 397.
Propeller Manual v1.0 · Page 345
Assembly Language Reference
FRQAs Counter A Frequency Register; p 397.
FRQBs Counter B Frequency Register; p 397.
PHSAs Counter A Phase Lock Loop (PLL) Register; p 397.
PHSBs Counter B Phase Lock Loop (PLL) Register; p 397.
VCFGs Video Configuration Register; p 397.
VSCLs Video Scale Register; p 397.
PARs Cog Boot Parameter Register (read only); p 397.
Constants
NOTE: Refer to Constants (pre-defined) in Chapter 4: Spin Language Reference.
TRUEs Logical true: -1 ($FFFFFFFF); p 202.
s
FALSE Logical false: 0 ($00000000); p 202.
s
POSX Maximum positive integer: 2,147,483,647 ($7FFFFFFF); p 203.
s
NEGX Maximum negative integer: -2,147,483,648 ($80000000); p 203.
s
PI Floating-point value for PI: ~3.141593 ($40490FDB); p 203.
Unary Operators
NOTE: All operators shown are constant-expression operators.
+ Positive (+X) unary form of Add; p 391.
- Negate (−X); unary form of Subtract; p 391.
^^ Square root; p 391.
|| Absolute Value; p 391.
|< Decode value (0-31) into single-high-bit long; p 391.
>| Encode long into value (0 - 32) as high-bit priority; p 391.
! Bitwise: NOT; p 391.
@ Address of symbol; p 391.
Binary Operators
NOTE: All operators shown are constant expression operators.
+ Add; p 391.
- Subtract; p 391.
* Multiply and return lower 32 bits (signed); p 391.
** Multiply and return upper 32 bits (signed); p 391.
/ Divide and return quotient (signed); p 391.
// Divide and return remainder (signed); p 391.
#> Limit minimum (signed); p 391.
<# Limit maximum (signed); p 391.
~> Shift arithmetic right; p 391.
<< Bitwise: Shift left; p 391.
>> Bitwise: Shift right; p 391.
<- Bitwise: Rotate left; p 391.
-> Bitwise: Rotate right; p 391.
>< Bitwise: Reverse; p 391.
& Bitwise: AND; p 391.
| Bitwise: OR; p 391.
^ Bitwise: XOR; p 391.
AND Boolean: AND (promotes non-0 to -1); p 391.
OR Boolean: OR (promotes non-0 to -1); p 391.
== Boolean: Is equal; p 391.
<> Boolean: Is not equal; p 391.
< Boolean: Is less than (signed); p 391.
> Boolean: Is greater than (signed); p 391.
=< Boolean: Is equal or less (signed); p 391.
=> Boolean: Is equal or greater (signed); p 391.
Syntax Definitions
In addition to detailed descriptions, the following pages contain syntax definitions for many
elements that describe, in short terms, all the options of that element. The syntax definitions
use special symbols to indicate when and how certain element features are to be used.
• Label is an optional statement label. Label can be global (starting with an underscore
‘_’ or a letter) or can be local (starting with a colon ‘:’). Local Labels must be
separated from other same-named local labels by at least one global label. Label is
used by instructions like JMP, CALL and COGINIT to designate the target destination.
• Condition is an optional execution condition (IF_C, IF_Z, etc.) that causes Instruction
to be executed or not. See Conditions on page 368 for more information.
• Instruction is a Propeller Assembly instruction (MOV, ADD, COGINIT, etc.) and its
operands.
• Effects is an optional list of one to three execution effects (WZ, WC, WR, and NR) to apply
to the instruction, if executed. They cause the Instruction to modify the Z flag, C
flag, and to write, or not write, the instruction’s result value to the destination
register, respectively. See Effects on page 371 for more information.
Page 348 · Propeller Manual v1.0
5: Assembly Language Reference
Since every instruction can include these three optional fields (Label, Condition, and Effects),
for simplicity those common fields are intentionally left out of the instruction’s syntax
description.
So, when you read a syntax description such as this:
This rule applies only to Propeller Assembly instructions; it does not apply to Propeller
Assembly directives.
Many syntax definitions end with a table similar to the one below. This table lists the
instruction’s 32-bit opcode, outputs and number of clock cycles. The opcode consists of the
instruction bits (–INSTR–), the “effect” status for the Z flag, C flag, result and
indirect/immediate status (ZCRI), the conditional execution bits (–CON–), and the destination
and source bits (–DEST- and –SRC–). The meaning of the Z and C flags, if any, is shown in the
Z Result and C Result fields; indicating the meaning of a 1 in those flags. The Result field shows
the instruction’s default behavior for writing or not writing the instruction’s result value. The
Clocks field shows the number of clocks the instruction requires for execution.
ABS
Instruction: Get the absolute value of a number.
Explanation
ABS takes the absolute value of SValue and writes the result into AValue.
If the WZ effect is specified, the Z flag is set (1) if SValue is zero. If the WC effect is specified,
the C flag is set (1) if SValue is negative, or cleared (0) if SValue is positive. The result is
written to AValue unless the NR effect is specified.
Literal SValues are zero-extended, so ABS is really best used with register SValues.
• NValue (d-field) is the register in which to write the negative of SValue’s absolute
value.
• SValue (s-field) is a register or a 9-bit literal whose absolute negative value will be
written to NValue.
Explanation
ABSNEG negates the absolute value of SValue and writes the result into NValue.
If the WZ effect is specified, the Z flag is set (1) if SValue is zero. If the WC effect is specified,
the C flag is set (1) if SValue is negative, or cleared (0) if SValue is positive. The result is
written to NValue unless the NR effect is specified.
Literal SValues are zero-extended, so ABS is really best used with register SValues.
ADD
Instruction: Add two unsigned values.
• Value1 (d-field) is the register containing the value to add to Value2 and is the
destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value is added into Value1.
ADDABS
Instruction: Add an absolute value to another value.
• Value (d-field) is the register containing the value to add to the absolute of SValue and
is the destination in which to write the result.
• SValue (s-field) is a register or a 9-bit literal whose absolute value is added into Value.
Explanation
ADDABS sums Value and the absolute of SValue together and stores the result into the Value
register.
If the WZ effect is specified, the Z flag is set (1) if Value + |SValue| equals zero. If the WC
effect is specified, the C flag is set (1) if the summation resulted in an unsigned carry (32-bit
overflow). The result is written to Value unless the NR effect is specified.
• SValue1 (d-field) is the register containing the value to add to SValue2 and is the
destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value is added into SValue1.
Explanation
ADDS sums the two signed values of SValue1 and SValue2 together and stores the result into
the SValue1 register.
If the WZ effect is specified, the Z flag is set (1) if SValue1 + SValue2 equals zero. If the WC
effect is specified, the C flag is set (1) if the summation resulted in a signed overflow. The
result is written to SValue1 unless the NR effect is specified.
ADDSX
Instruction: Add two signed values plus C.
• SValue1 (d-field) is the register containing the value to add to SValue2 plus C, and is
the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value plus C is added into
SValue1.
ADDX
Instruction: Add two unsigned values plus C.
• Value1 (d-field) is the register containing the value to add to Value2 plus C, and is the
destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value plus C is added into Value1.
Explanation
ADDX (Add Extended) sums the two unsigned values of Value1 and Value2 plus C, and stores
the result into the Value1 register. Use the ADDX instruction after an ADD or ADDX (with the WC,
and optionally WZ, effect) to perform multi-long additions; 64-bit additions, for example.
If the WZ effect is specified, the Z flag is set (1) if Z was previously set and Value1 + Value2 +
C equals zero (use WC and WZ on preceding ADD or ADDX instruction). If the WC effect is
specified, the C flag is set (1) if the summation resulted in an unsigned carry (32-bit
overflow). The result is written to Value1 unless the NR effect is specified.
• Value1 (d-field) is the register containing the value to bitwise AND with Value2 and is
the destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value is bitwise ANDed with
Value1.
Explanation
AND (bitwise AND) performs a bitwise AND of the value in Value2 into that of Value1.
If the WZ effect is specified, the Z flag is set (1) if Value1 AND Value2 equals zero. If the WC
effect is specified, the C flag is set (1) if the result contains an odd number of high (1) bits.
The result is written to Value1 unless the NR effect is specified.
ANDN
Instruction: Bitwise AND a value with the NOT of another.
• Value1 (d-field) is the register containing the value to bitwise AND with !Value2 and
is the destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value is inverted (bitwise NOT)
and bitwise ANDed with Value1.
Explanation
ANDN (bitwise AND NOT) performs a bitwise AND of the inverted value (bitwise NOT) of
Value2 into that of Value1.
If the WZ effect is specified, the Z flag is set (1) if Value1 AND !Value2 equals zero. If the WC
effect is specified, the C flag is set (1) if the result contains an odd number of high (1) bits.
The result is written to Value1 unless the NR effect is specified.
CALL #Address
Result: PC + 1 is written to the s-field of the register indicated by the d-field.
• Address (s-field) is the register or 9-bit literal whose value is the address to jump to.
Explanation
CALL records the address of the next instruction (PC + 1) then jumps to Address. The routine
at Address should eventually execute a RET instruction to return to the recorded address (the
instruction following the CALL).
The Propeller does not use a call stack, so the return address is stored in a different manner; it
is recorded at the location of the routine’s RET command itself. For the CALL instruction, the
assembler searches for a label that is Address with “_ret” appended to it. It then encodes the
address of the label Address_ret into the CALL instruction as well as the Address you specified
to jump to. At run time, when executing the CALL instruction, the cog first stores the return
address (PC + 1) into the source field of the “RET” instruction at Address_ret and then jumps
to Address. See the example below:
call Routine
<other code here>
In this example, the first instruction is a call to Routine. The assembler searches for another
label called Routine_ret and encodes its address as well as Routine’s address into the CALL
instruction. At run time, when executing the CALL instruction, the cog first writes the address
of <other code here> into the source field of the instruction at Routine_ret, then jumps to
CLKSET
Instruction: Set the clock mode at run time.
CLKSET Mode
• Mode (d-field) is the register containing the 8-bit pattern to write to the CLK register.
Explanation
CLKSET changes the System Clock mode during run time. The CLKSET instruction behaves
similar to the Spin command of the same name (see CLKSET on page 183) except that it only
sets the clock mode, not the frequency.
After issuing a CLKSET instruction, it is important to update the System Clock Frequency
value by writing to its location in Main RAM (long 0): WRLONG freqaddr, #0. If the System
Clock Frequency value is not updated, other objects will misbehave due to invalid clock
frequency data.
CLKSET is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
CMP
Instruction: Compare two unsigned values.
• Value1 (d-field) is the register containing the value to compare with that of Value2.
• Value2 (s-field) is a register or a 9-bit literal whose value is compared with Value1.
Explanation
CMP (Compare Unsigned) compares the unsigned values of Value1 and Value2. The Z and C
flags, if written, indicate the relative equal, and greater or lesser relationship between the two.
If the WZ effect is specified, the Z flag is set (1) if Value1 equals Value2. If the WC effect is
specified, the C flag is set (1) if Value1 is less than Value2.
CMPS
Instruction: Compare two signed values.
• SValue1 (d-field) is the register containing the value to compare with that of SValue2.
• SValue2 (s-field) is a register or a 9-bit literal whose value is compared with SValue1.
Explanation
CMPS (Compare Signed) compares the signed values of SValue1 and SValue2. The Z and C
flags, if written, indicate the relative equal, and greater or lesser relationship between the two.
Page 362 · Propeller Manual v1.0
5: Assembly Language Reference – CMPSUB
If the WZ effect is specified, the Z flag is set (1) if SValue1 equals SValue2. If the WC effect is
specified, the C flag is set (1) if SValue1 is less than or equal to SValue2.
CMPSUB
Instruction: Compare two unsigned values and subtract the second if it is lesser or equal.
• Value1 (d-field) is the register containing the value to compare with that of Value2 and
is the destination in which to write the result if a subtraction is performed.
• Value2 (s-field) is a register or a 9-bit literal whose value is compared with and
possibly subtracted from Value1.
Explanation
CMPSUB compares the unsigned values of Value1 and Value2, and if Value2 is equal to or
greater than Value1 then it is subtracted from Value1 (if the WR effect is specified). The Z and
C flags, if written, indicate the relative equal, and greater or lesser relationship between the
two.
If the WZ effect is specified, the Z flag is set (1) if Value1 equals Value2. If the WC effect is
specified, the C flag is set (1) if Value1 is equal to or greater than Value2. If the WR effect is
specified, the result, if any, is written to Value1.
• SValue1 (d-field) is the register containing the value to compare with that of SValue2.
• SValue2 (s-field) is a register or a 9-bit literal whose value is compared with SValue1.
Explanation
CMPSX (Compare Signed, Extended) compares the signed values of SValue1 and SValue2 plus
C. Use the CMPSX instruction after a CMP or CMPX (with the WC, and optionally WZ, effect) to
perform multi-long, signed comparisons; 64-bit signed comparisons, for example. The Z and
C flags, if written, indicate the relative equal, and greater or lesser relationship between the
two.
If the WZ effect is specified, the Z flag is set (1) if Z was previously set and SValue1 equals
SValue2 + C (use WC and WZ on preceding CMP or CMPX instruction). If the WC effect is
specified, the C flag is set (1) if SValue1 is less than SValue2 (as multi-long values).
Note that in a multi-long signed operation, the first instruction is unsigned (ex: CMP), any
middle instructions are unsigned, extended (ex: CMPX), and the last instruction is signed,
extended (ex: CMPSX).
CMPX
Instruction: Compare two unsigned values plus C.
• Value1 (d-field) is the register containing the value to compare with that of Value2.
• Value2 (s-field) is a register or a 9-bit literal whose value is compared with Value1.
Explanation
CMPX (Compare Extended) compares the unsigned values of Value1 and Value2 plus C. Use
the CMPX instruction after a CMP or CMPX (with the WC, and optionally WZ, effect) to perform
multi-long comparisons; 64-bit unsigned comparisons, for example. The Z and C flags, if
written, indicate the relative equal, and greater or lesser relationship between the two.
If the WZ effect is specified, the Z flag is set (1) if Z was previously set and Value1 equals
Value2 + C (use WC and WZ on preceding CMP or CMPX instruction). If the WC effect is specified,
the C flag is set (1) if Value1 is less than Value2 (as multi-long values).
COGID
Instruction: Get current cog’s ID.
COGID Destination
Result: The current cog’s ID (0-7) is written to Destination.
Explanation
COGID returns the ID of the cog that executed the command. The COGID instruction behaves
similar to the Spin command of the same name; see COGID on page 186.
If the WZ effect is specified, the Z flag is set if the cog ID is zero. The result is written to
Destination unless the NR effect is specified.
COGID is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
COGINIT Destination
Result: Optionally, the started/restarted cog’s ID (0-7) is written to Destination.
• Destination (d-field) is the register containing startup information for the target cog
and optionally becomes the destination of the started cog’s ID if a new cog is started.
Explanation
The COGINIT instruction behaves similar to two Spin commands, COGNEW and COGINIT, put
together. Propeller Assembly’s COGINIT instruction can be used to start a new cog or restart
an active cog. The Destination register has four fields that determine which cog is started,
where its program begins in main memory, and what its PAR register will contain. The table
below describes these fields.
Table 5-1: Destination Register Fields
31:18 17:4 3 2:0
14-bit Long address for PAR Register 14-bit Long address of code to load New Cog ID
The first field, bits 31:18, will be written to the started cog’s PAR register bits 15:2. This is
14-bits total that are intended to be the upper bits of a 16-bit long address. Similar to the
Parameter field of Spin’s version of COGINIT, this first field of Destination is used to pass the
14-bit address of an agreed-upon memory location or structure to the started cog.
The second field, bits 17:4, holds the upper 14-bits of a 16-bit long address pointing to the
desired assembly program to load into the cog. Cog registers $000 through $1EF will be
loaded sequentially starting at this address, the special purpose registers will be cleared to
zero (0), and the cog will start executing the code at register $000.
The third field, bit 3, should be set (1) if a new cog should be started, or cleared (0) if a
specific cog should be started or restarted.
COGSTOP
Instruction: Start a cog by its ID.
COGSTOP CogID
Explanation
The COGSTOP instruction stops a cog whose ID is in the register CogID; placing that cog into a
dormant state. In the dormant state, the cog ceases to receive System Clock pulses so that
power consumption is greatly reduced.
COGSTOP is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
Conditions ( IF_x )
Every Propeller Assembly instruction has an optional “condition” field that is used to
dynamically determine whether or not it executes when it is reached at run time. The basic
syntax for Propeller Assembly instructions is:
〈Label〉 〈Condition〉 Instruction 〈Effects〉
The optional Condition field can contain one of 32 conditions (see Table 5-2) and defaults to
IF_ALWAYS when no condition is specified. The 4-bit Value shown for each condition is the
value used for the –CON– field in the instruction’s opcode.
This feature, along with proper use of instructions’ optional Effects field, makes Propeller
Assembly very powerful. Flags can be affected at will and later instructions can be
conditionally executed based on the results. Here’s an example:
test _pins, #$20 wc
and _pins, #$38
shl t1, _pins
shr _pins, #3
movd vcfg, _pins
if_nc mov dira, t1
if_nc mov dirb, #0
if_c mov dira, #0
if_c mov dirb, t1
The first instruction, test _pins, #$20 wc, performs its operation and adjusts the state of
the C flag because the WC effect was specified. The next four instructions perform operations
that could affect the C flag, but they do not affect it because no WC effect was specified. This
means that the state of the C flag is preserved since it was last modified by the first
instruction. The last four instructions are conditionally executed based on the state of the C
flag that was set five instructions prior. Among the last for instructions, the first two mov
instructions have if_nc conditions, causing them to execute only “if not C” (if C = 0). The
last two mov instructions have if_c conditions, causing them to execute only “if C” (if C = 1).
In this case, the two pairs of mov instructions are executed in a mutually-exclusive fashion.
When an instruction’s condition evaluates to FALSE, the instruction dynamically becomes a
NOP, elapsing 4 clock cycles but affecting no flags or registers. This makes multi-decision
code such as this example very deterministically timed.
DJNZ
Instruction: Decrement value and jump to address if not zero.
Explanation
DJNZ decrements the Value register and jumps to Address if the result is not zero.
When the WZ effect is specified, the Z flag is set (1) if the decremented Value is zero. When
the WC effect is specified, the C flag is set (1) if the decrement results in an underflow. The
decremented result is written to Value unless the NR effect is specified.
DJNZ requires a different amount of clock cycles depending on whether or not it has to jump.
If it must jump it takes 4 clock cycles, if no jump occurs it takes 8 clock cycles. Since loops
utilizing DJNZ need to be fast, it is optimized in this way for speed.
Effects
Every Propeller Assembly instruction has an optional “effects” field that causes it to modify a
flag or register when it executes. The basic syntax for Propeller Assembly instructions is:
The optional Effects field can contain one of four conditions, shown below. For any effect
not specified, the default behavior remains as indicated by the corresponding bit (Z, C, or R)
in the ZCRI field of the instruction’s opcode.
Follow an instruction with one to three space-delimited Effects to cause that instruction to
affect the indicated item. For example:
and temp1, #$20 wc
andn temp2, #$38 wz, nr
The first instruction performs a bitwise AND of the value in the temp1 register with $20,
stores the result in temp1 and modifies with C flag with the parity of the result. The second
instruction performs a bitwise AND NOT of the value in the temp2 register with $38,
modifies the Z flag according to whether or not the result is zero, and does not write the result
to temp2. During the execution of the first instruction, the Z flag is not altered. During the
execution of the second instruction, the C flag is not altered. If these instructions did not
include the WC and WZ effects, those flags would not be altered at all.
Using Effects on instructions, along with Conditions on later instructions, enables code to be
much more powerful than what is possible with typical assembly languages. See Conditions
on page 368 for more information.
FIT 〈Address〉
Result: Compile-time error if previous instructions/data exceed Address-1.
• Address is an optional Cog RAM address (0-$1F0) for which prior assembly code
should not reach. If Address is not given, the value $1F0 is used (the address of the
first special purpose register).
Explanation
The FIT directive checks the current compile-time cog address pointer and generates an error
if it is beyond Address-1 or if it is beyond $1EF (the end of general purpose Cog RAM). This
directive can be used to ensure that the previous instructions and data fit within Cog RAM, or
a limited region of Cog RAM. Note: any instructions that do not fit in Cog RAM will be left
out when the assembly code is launched into the cog. Consider the following example:
DAT
ORG 492
Toggle mov dira, Pin
:Loop mov outa, Pin
mov outa, #0
jmp #:Loop
FIT
This code was artificially pushed into upper Cog RAM space by the ORG statement, causing
the code to overlap the first special purpose register ($1F0) and causing the FIT directive to
cause a compile-time error when the code is compiled.
HUBOP
Instruction: Perform a hub operation.
Explanation
HUBOP is the template for every hub operation instruction in the Propeller chip: CLKSET, COGID,
COGINIT, COGSTOP, LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR. The instructions that perform hub
operations set the Operation field (s-field of the opcode) to the 3-bit immediate value that
represents the desired operation (see the opcode of the hub instruction’s syntax description
for more information). The HUBOP instruction itself should rarely be used, but may be handy
for special situations.
HUBOP is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
IF_x
See Conditions on page 368.
• Address (s-field) is the register or a 9-bit literal whose value is the address to jump to.
Explanation
JMP sets the Program Counter (PC) to Address causing execution to jump that location in Cog
RAM.
JMPRET
Instruction: Jump to address with intention to “return” to another address.
• RetInstAddr (d-field) is the register in which to store the return address (PC + 1); it
should be the address of an appropriate RET or JMP instruction for DestAddress.
• DestAddress (s-field) is the register or 9-bit literal whose value is the address to jump
to.
Explanation
JMPRET stores the address of the next instruction (PC + 1) into the source field of the
instruction at RetInstAddr, then jumps to DestAddress. The routine at DestAddress should
eventually execute the RET or JMP instruction at the RetInstAddr to return to the stored address
(the instruction following the JMPRET).
LOCKCLR
Instruction: Clear lock to false and get its previous state.
LOCKCLR ID
Result: Optionally, previous state of lock is written to C flag.
Explanation
LOCKCLR is one of four lock instructions (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKCLR clears the
lock described by the register ID to zero (0) and returns the previous state of that lock in the
C flag; if the WC effect is specified. The LOCKCLR instruction behaves similar to Spin’s LOCKCLR
command; see LOCKCLR on page 228.
LOCKCLR is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
LOCKNEW
Instruction: Check out a new lock and get its ID.
LOCKNEW NewID
Result: The new lock’s ID (0-7) is written to NewID.
• NewID (d-field) is the register where the newly checked-out lock’s ID is written.
Explanation
LOCKNEW is one of four lock instructions (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKNEW checks out
a unique lock, from the hub, and retrieves the ID of that lock. The LOCKNEW instruction
behaves similar to Spin’s LOCKNEW command; see LOCKNEW on page 230.
If the WZ effect is specified, the Z flag is set (1) if the returned ID is zero (0). If the WC effect
is specified, the C flag is set if no lock was available for checking out. The ID of the newly
checked-out lock is written to NewID unless the NR effect is specified.
LOCKNEW is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
LOCKRET
Instruction: Release lock back for future “new lock” requests.
LOCKRET ID
• ID (d-field) is the register containing the ID (0 – 7) of the lock to return to the lock
pool.
LOCKSET
Instruction: Set lock to true and get its previous state.
LOCKSET ID
Result: Optionally, previous state of lock is written to C flag.
Explanation
LOCKSET is one of four lock instructions (LOCKNEW, LOCKRET, LOCKSET, and LOCKCLR) used to
manage resources that are user-defined and deemed mutually-exclusive. LOCKSET sets the
lock described by the register ID to one (1) and returns the previous state of that lock in the C
flag; if the WC effect is specified. The LOCKSET instruction behaves similar to Spin’s LOCKSET
command; see LOCKSET on page 234.
LOCKSET is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
MAX
Instruction: Limit maximum of unsigned value to another unsigned value.
• Value1 (d-field) is the register containing the value to compare against Value2 and is
the destination in which to write the lesser of the two.
• Value2 (s-field) is a register or a 9-bit literal whose value is compared against Value1.
Explanation
MAX compares the unsigned values of Value1 and Value2 and stores the lesser of the two into
the Value1 register, effectively limiting Value1 to a maximum of Value2.
If the WZ effect is specified, the Z flag is set (1) if Value1 and Value2 are equal. If the WC
effect is specified, the C flag is set (1) if the unsigned Value1 is less than the unsigned
Value2. The lesser of the two values is written to Value1 unless the NR effect is specified.
MAXS
Instruction: Limit maximum of signed value to another signed value.
• SValue1 (d-field) is the register containing the value to compare against SValue2 and
is the destination in which to write the lesser of the two.
• SValue2 (s-field) is a register or a 9-bit literal whose value is compared against
SValue1.
MIN
Instruction: Limit minimum of unsigned value to another unsigned value.
• Value1 (d-field) is the register containing the value to compare against Value2 and is
the destination in which to write the greater of the two.
• Value2 (s-field) is a register or a 9-bit literal whose value is compared against Value1.
Explanation
MIN compares the unsigned values of Value1 and Value2 and stores the greater of the two into
the Value1 register, effectively limiting Value1 to a minimum of Value2.
If the WZ effect is specified, the Z flag is set (1) if Value1 and Value2 are equal. If the WC
effect is specified, the C flag is set (1) if the unsigned Value1 is less than the unsigned
Value2. The greater of the two values is written to Value1 unless the NR effect is specified.
• SValue1 (d-field) is the register containing the value to compare against SValue2 and
is the destination in which to write the greater of the two.
• SValue2 (s-field) is a register or a 9-bit literal whose value is compared against
SValue1.
Explanation
MINS compares the signed values of SValue1 and SValue2 and stores the greater of the two
into the SValue1 register, effectively limiting SValue1 to a minimum of SValue2.
If the WZ effect is specified, the Z flag is set (1) if SValue1 and SValue2 are equal. If the WC
effect is specified, the C flag is set (1) if the signed SValue1 is less than the signed SValue2.
The greater of the two values is written to SValue1 unless the NR effect is specified.
MOV
Instruction: Set a register to a value.
MOVD
Instruction: Set a register’s destination field to a value.
• Destination (d-field) is the register whose destination field (bits 17..9) is set to Value’s
value.
• Value (s-field) is a register or a 9-bit literal whose value is stored into Destination’s d-
field.
Explanation
MOVD copies the 9-bit value of Value into Destination’s d-field (destination field) bits 17..9.
Destination’s other bits are left unchanged. This instruction is handy for setting certain
registers like CTRA and VCFG, and for updating the destination field of instructions in self-
modifying code.
If the WZ effect is specified, the Z flag is set (1) if Value equals zero. The result is written to
Destination unless the NR effect is specified.
• Destination (d-field) is the register whose instruction and effects fields (bits 31..23) are
set to Value’s value.
• Value (s-field) is a register or a 9-bit literal whose value is stored into Destination’s
instruction and effects field.
Explanation
MOVI copies the 9-bit value of Value into Destination’s instruction and effects fields bits
31..23. Destination’s other bits are left unchanged. This instruction is handy for setting
certain registers like CTRA and VCFG, and for updating the instruction and effects fields of
instructions in self-modifying code.
If the WZ effect is specified, the Z flag is set (1) if Value equals zero. The result is written to
Destination unless the NR effect is specified.
MOVS
Instruction: Set a register’s source field to a value.
• Destination (d-field) is the register whose source field (bits 8..0) is set to Value’s
value.
• Value (s-field) is a register or a 9-bit literal whose value is stored into Destination’s
source field.
Explanation
MOVS copies the 9-bit value of Value into Destination’s source field (s-field) bits 8..0.
Destination’s other bits are left unchanged. This instruction is handy for setting certain
registers like CTRA and VCFG, and for updating the source field of instructions in self-
modifying code.
If the WZ effect is specified, the Z flag is set (1) if Value equals zero. The result is written to
Destination unless the NR effect is specified.
MUXC
Instruction: Set discrete bits of a value to the state of C.
• Destination (d-field) is the register whose bits described by Mask are affected by C.
• Mask (s-field) is a register or a 9-bit literal whose value contains high (1) bits for
every bit in Destination to set to the C flag’s state.
Explanation
MUXC sets each bit of the value in Destination, which corresponds to Mask’s high (1) bits, to
the C state. All bits of Destination that are not targeted by high (1) bits of Mask are
unaffected. This instruction is handy for setting or clearing discrete bits, or groups of bits, in
an existing value.
If the WZ effect is specified, the Z flag is set (1) if Destination’s final value is 0. If the WC
effect is specified, the C flag is set (1) if the resulting Destination contains an odd number of
high (1) bits. The result is written to Destination unless the NR effect is specified.
MUXNC
Instruction: Set discrete bits of a value to the state of !C.
• Destination (d-field) is the register whose bits described by Mask are affected by !C.
• Mask (s-field) is a register or a 9-bit literal whose value contains high (1) bits for
every bit in Destination to set to the inverse of the C flag’s state.
Explanation
MUXNC sets each bit of the value in Destination, which corresponds to Mask’s high (1) bits, to
the !C state. All bits of Destination that are not targeted by high (1) bits of Mask are
unaffected. This instruction is handy for setting or clearing discrete bits, or groups of bits, in
an existing value.
If the WZ effect is specified, the Z flag is set (1) if Destination’s final value is 0. If the WC
effect is specified, the C flag is set (1) if the resulting Destination contains an odd number of
high (1) bits. The result is written to Destination unless the NR effect is specified.
MUXNZ
Instruction: Set discrete bits of a value to the state of !Z.
• Destination (d-field) is the register whose bits described by Mask are affected by !Z.
• Mask (s-field) is a register or a 9-bit literal whose value contains high (1) bits for
every bit in Destination to set to the inverse of the Z flag’s state.
MUXZ
Instruction: Set discrete bits of a value to the state of Z.
• Destination (d-field) is the register whose bits described by Mask are affected by Z.
• Mask (s-field) is a register or a 9-bit literal whose value contains high (1) bits for
every bit in Destination to set to the Z flag’s state.
Explanation
MUXZ sets each bit of the value in Destination, which corresponds to Mask’s high (1) bits, to
the Z state. All bits of Destination that are not targeted by high (1) bits of Mask are
unaffected. This instruction is handy for setting or clearing discrete bits, or groups of bits, in
an existing value.
If the WZ effect is specified, the Z flag is set (1) if Destination’s final value is 0. If the WC
effect is specified, the C flag is set (1) if the resulting Destination contains an odd number of
high (1) bits. The result is written to Destination unless the NR effect is specified.
NEG
Instruction: Get the negative of a number.
Explanation
NEG stores negative SValue into NValue.
If the WZ effect is specified, the Z flag is set (1) if SValue is zero. If the WC effect is specified,
the C flag is set (1) if SValue is negative or cleared (0) if SValue is positive. The result is
written to NValue unless the NR effect is specified.
NEGC
Instruction: Get a value, or its additive inverse, based on C.
NEGNC
Instruction: Get a value, or its additive inverse, based on !C.
Explanation
NEGNC stores –Value (if C = 0) or Value (if C = 1) into RValue.
If the WZ effect is specified, the Z flag is set (1) if Value is zero. If the WC effect is specified,
the C flag is set (1) if Value is negative or cleared (0) if Value is positive. The result is
written to RValue unless the NR effect is specified.
NEGNZ
Instruction: Get a value, or its additive inverse, based on !Z.
Explanation
NEGNZ stores –Value (if Z = 0) or Value (if Z = 1) into RValue.
If the WZ effect is specified, the Z flag is set (1) if Value is zero. If the WC effect is specified,
the C flag is set (1) if Value is negative or cleared (0) if Value is positive. The result is
written to RValue unless the NR effect is specified.
NEGZ
Instruction: Get a value, or its additive inverse, based on Z.
Explanation
NEGZ stores Value (if Z = 0) or –Value (if Z = 1) into RValue.
If the WZ effect is specified, the Z flag is set (1) if Value is zero. If the WC effect is specified,
the C flag is set (1) if Value is negative or cleared (0) if Value is positive. The result is
written to RValue unless the NR effect is specified.
NOP
Instruction: No operation, just elapse four clock cycles.
NOP
–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks
------ ---- 0000 --------- --------- --- --- --- 4
Explanation
NOP performs no operation but consumes 4 clock cycles. NOP has its –CON– field set to all
zeros, the NEVER condition; effectively, every instruction with a NEVER condition is a NOP
instruction.
Operators
Propeller Assembly code can contain constant expressions, and those expressions may use
any operators that are allowed in constant expressions. Table 5-4 summarizes all the
operators allowed in Propeller Assembly code (all those allowed in constant expressions).
Please refer to the Spin Language Reference Operators section for detailed descriptions of
their functions; page numbers for each operator are given in Table 5-4
OR
Instruction: Bitwise OR two values.
• Value1 (d-field) is the register containing the value to bitwise OR with Value2 and is
the destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value is bitwise ORed with
Value1.
Explanation
OR (bitwise inclusive OR) performs a bitwise OR of the value in Value2 into that of Value1.
If the WZ effect is specified, the Z flag is set (1) if Value1 OR Value2 equals zero. If the WC
effect is specified, the C flag is set (1) if the result contains an odd number of high (1) bits.
The result is written to Value1 unless the NR effect is specified.
ORG
Directive: Adjust compile-time cog address pointer.
ORG 〈Address〉
• Address is an optional Cog RAM address (0-495) to assemble the following assembly
code into. If Address is not given, the value 0 is used.
Explanation
The ORG (origin) directive sets the Propeller Tool’s assembly pointer to a new value
representing the Cog RAM position to use for the following assembly code. ORG typically
appears at the start of any new assembly code intended for a cog.
The ORG statement in this example sets the assembly pointer to zero (0), so the next
instruction, mov dira, Pin, is assembled into Cog RAM location 0, the instruction after that
is assembled into Cog RAM location 1, etc.
RCL
Instruction: Rotate C left into value by specified number of bits.
Explanation
RCL (Rotate Carry Left) performs a rotate left of Value, Bits times, using the C flag’s original
value for each of the LSBs affected.
If the WZ effect is specified, the Z flag is set (1) if the resulting Value equals zero. If the WC
effect is specified, at the end of the operation, the C flag is set equal to Value’s original bit
31. The result is written to Value unless the NR effect is specified.
Explanation
RCR (Rotate Carry Right) performs a rotate right of Value, Bits times, using the C flag’s
original value for each of the MSBs affected.
If the WZ effect is specified, the Z flag is set (1) if the resulting Value equals zero. If the WC
effect is specified, at the end of the operation, the C flag is set equal to Value’s original bit 0.
The result is written to Value unless the NR effect is specified.
RDBYTE
Instruction: Read byte of main memory.
• Value (d-field) is the register to store the zero-extended byte value into.
• Address (s-field) is a register or a 9-bit literal whose value is the main memory
address to read from.
RDLONG
Instruction: Read long of main memory.
Explanation
RDLONG syncs to the Hub, reads the long of main memory at Address, and stores it into the
Value register.
If the WZ effect is specified, the Z flag will be set (1) if the value read from main memory is
zero. The value from main memory will be written to Value unless the NR effect is specified.
RDLONG is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
• Value (d-field) is the register to store the zero-extended word value into.
• Address (s-field) is a register or a 9-bit literalwhose value is the main memory address
to read from.
Explanation
RDWORD syncs to the Hub, reads the word of main memory at Address, zero-extends it, and
stores it into the Value register.
If the WZ effect is specified, the Z flag will be set (1) if the value read from main memory is
zero. The value from main memory will be written to Value unless the NR effect is specified.
RDWORD is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
Registers
Each cog contains 16 special purpose registers for accessing I/O pins, the built-in counters
and video generator, and the parameter passed at the moment the cog is launched. All of
these registers are explained in the Spin Language Reference and most of the information
applies to both Spin and Propeller Assembly. The following table illustrates the 16 special
purpose registers, indicates where to find information and what details, if any, do not apply to
Propeller Assembly.
Each of these registers can be accessed just like any other register in the Destination or
Source fields of instructions, except for those that are designated “(Read-Only).” Read-only
registers can only be used in the Source field of an instruction.
Explanation
The RES (reserve) directive reserves one or more longs of Cog RAM by incrementing the
compile-time cog address pointer by Count. Normally this is used to reserve memory for an
assembly symbol. For example:
DAT
ORG 0
<some code here>
mov Time, cnt
add Time, Delay
waitcnt Time, Delay
<some code here>
The last line of the above example reserves one long of Cog RAM for the symbol Time. The
assembly code uses that symbol as a long variable; to create a delay of 6 million clock cycles,
in this case.
RET
Instruction: Return to address.
RET
–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks
010111 0001 1111 --------- --------- Result = 0 --- Not Written 4
Explanation
RET is a subset of the JMP instruction but with the i-field set and the s-field unspecified. The
RET instruction is meant to be used along with a label in the form “label_ret” and a CALL
instruction that targets RET’s routine, “label.” See CALL on page 360 for more information.
REV
Instruction: Reverse LSBs of value and zero-extend.
• Value (d-field) is the register containing the value whose bits are reversed.
• Bits (s-field) is a register or a 5-bit literal whose value subtracted from 32, (32 - Bits),
is the number of Value’s LSBs to reverse. The upper Bits MSBs of Value are
cleared.
Explanation
REV (Reverse) reverses the lower (32 - Bits) of Value’s LSB and clears the upper Bits of
Value’s MSBs.
If the WZ effect is specified, the Z flag is set (1) if the resulting Value equals zero. If the WC
effect is specified, the C flag is set equal to Value’s original bit 0. The result is written to
Value unless the NR effect is specified.
Explanation
ROL (Rotate Left) rotates Value left, Bits times. The MSBs rotated out of Value are rotated
into its LSBs.
If the WZ effect is specified, the Z flag is set (1) if the resulting Value equals zero. If the WC
effect is specified, at the end of the operation, the C flag is set equal to Value’s original bit
31. The result is written to Value unless the NR effect is specified.
ROR
Instruction: Rotate value right by specified number of bits.
SAR
Instruction: Shift value arithmetically right by specified number of bits.
Explanation
SAR (Shift Arithmetic Right) shifts Value right by Bits places, extending the MSB along the
way. This has the effect of preserving the sign in a signed value.
If the WZ effect is specified, the Z flag is set (1) if the resulting Value equals zero. If the WC
effect is specified, the C flag is set equal to Value’s original bit 0. The result is written to
Value unless the NR effect is specified.
SHL
Instruction: Shift value left by specified number of bits.
Explanation
SHL (Shift Left) shifts Value left by Bits places.
If the WZ effect is specified, the Z flag is set (1) if the resulting Value equals zero. If the WC
effect is specified, the C flag is set equal to Value’s original bit 31. The result is written to
Value unless the NR effect is specified.
SHR
Instruction: Shift value right by specified number of bits.
SUB
Instruction: Subtract two unsigned values.
• Value1 (d-field) is the register containing the value to subtract Value2 from, and is the
destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value is subtracted from Value1.
Explanation
SUB subtracts the unsigned Value2 from the unsigned Value1 and stores the result into the
Value1 register.
If the WZ effect is specified, the Z flag is set (1) if Value1 − Value2 equals zero. If the WC
effect is specified, the C flag is set (1) if the subtraction resulted in an unsigned borrow (32-
bit underflow). The result is written to Value1 unless the NR effect is specified.
SUBABS
Instruction: Subtract an absolute value from another value.
• Value (d-field) is the register containing the value to subtract the absolute of SValue
from, and is the destination in which to write the result.
• SValue (s-field) is a register or a 9-bit literal whose absolute value is subtracted from
Value.
Explanation
SUBABS subtracts the absolute of SValue from Value and stores the result into the Value
register.
If the WZ effect is specified, the Z flag is set (1) if Value − |SValue| equals zero. If the WC
effect is specified, the C flag is set (1) if the subtraction resulted in an unsigned borrow (32-
bit underflow). The result is written to Value unless the NR effect is specified.
SUBS
Instruction: Subtract two signed values.
• SValue1 (d-field) is the register containing the value to subtract SValue2 from, and is
the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value is subtracted from SValue1.
SUBSX
Instruction: Subtract signed value plus C from another signed value.
• SValue1 (d-field) is the register containing the value to subtract SValue2 plus C from,
and is the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value plus C is subtracted from
SValue1.
Explanation
SUBSX (Subtract Signed, Extended) subtracts the signed value of SValue2 plus C from
SValue1, and stores the result into the SValue1 register. Use the SUBSX instruction after a SUB
or SUBX (with the WC, and optionally WZ, effect) to perform multi-long, signed subtractions; 64-
bit subtractions, for example.
If the WZ effect is specified, the Z flag is set (1) if Z was previously set and SValue1 −
(SValue2 + C) equals zero (use WC and WZ on preceding SUB or SUBX instruction). If the WC
effect is specified, the C flag is set (1) if the subtraction resulted in a signed underflow. The
result is written to SValue1 unless the NR effect is specified.
Note that in a multi-long signed operation, the first instruction is unsigned (ex: SUB), any
middle instructions are unsigned, extended (ex: SUBX), and the last instruction is signed,
extended (ex: SUBSX).
• Value1 (d-field) is the register containing the value to subtract Value2 plus C from,
and is the destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value plus C is subtracted from
Value1.
Explanation
SUBX (Subtract Extended) subtracts the unsigned value of Value2 plus C from the unsigned
Value1 and stores the result into the Value1 register. Use the SUBX instruction after a SUB or
SUBX (with the WC, and optionally WZ, effect) to perform multi-long subtractions; 64-bit
subtractions, for example.
If the WZ effect is specified, the Z flag is set (1) if Z was previously set and Value1 − (Value2
+ C) equals zero (use WC and WZ on preceding SUB or SUBX instruction). If the WC effect is
specified, the C flag is set (1) if the subtraction resulted in an unsigned borrow (32-bit
underflow). The result is written to Value1 unless the NR effect is specified.
SUMC
Instruction: Sum a signed value with another whose sign is inverted depending on C.
• SValue1 (d-field) is the register containing the value to sum with either –SValue2 or
SValue2, and is the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value is sign-affected by C and
summed into SValue1.
Page 406 · Propeller Manual v1.0
5: Assembly Language Reference – SUMNC
Explanation
SUMC (Sum with C-affected sign) adds the signed value of SValue1 to –SValue2 (if C = 1) or
to SValue2 (if C = 0) and stores the result into the SValue1 register.
If the WZ effect is specified, the Z flag is set (1) if SValue1 ± SValue2 equals zero. If the WC
effect is specified, the C flag is set (1) if the summation resulted in a signed overflow. The
result is written to SValue1 unless the NR effect is specified.
SUMNC
Instruction: Sum a signed value with another whose sign is inverted depending on !C.
• SValue1 (d-field) is the register containing the value to sum with either SValue2 or
-SValue2, and is the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value is sign-affected by !C and
summed into SValue1.
Explanation
SUMNC (Sum with !C-affected sign) adds the signed value of SValue1 to SValue2 (if C = 1) or
to –SValue2 (if C = 0) and stores the result into the SValue1 register.
If the WZ effect is specified, the Z flag is set (1) if SValue1 ± SValue2 equals zero. If the WC
effect is specified, the C flag is set (1) if the summation resulted in a signed overflow. The
result is written to SValue1 unless the NR effect is specified.
• SValue1 (d-field) is the register containing the value to sum with either SValue2 or
-SValue2, and is the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value is sign-affected by !Z and
summed into SValue1.
Explanation
SUMNZ (Sum with !Z-affected sign) adds the signed value of SValue1 to SValue2 (if Z = 1) or
to –SValue2 (if Z = 0) and stores the result into the SValue1 register.
If the WZ effect is specified, the Z flag is set (1) if SValue1 ± SValue2 equals zero. If the WC
effect is specified, the C flag is set (1) if the summation resulted in a signed overflow. The
result is written to SValue1 unless the NR effect is specified.
SUMZ
Instruction: Sum a signed value with another whose sign is inverted depending on Z.
• SValue1 (d-field) is the register containing the value to sum with either –SValue2 or
SValue2, and is the destination in which to write the result.
• SValue2 (s-field) is a register or a 9-bit literal whose value is sign-affected by Z and
summed into SValue1.
TEST
Instruction: Bitwise AND two values to affect flags only.
• Value1 (d-field) is the register containing the value to bitwise AND with Value2.
• Value2 (s-field) is a register or a 9-bit literal whose value is bitwise ANDed with
Value1.
Explanation
TEST is similar to AND except it doesn’t write a result to Value1; it performs a bitwise AND of
the values in Value1 and Value2 and optionally stores the zero-result and parity of the result
in the Z and C flags.
If the WZ effect is specified, the Z flag is set (1) if Value1 AND Value2 equals zero. If the WC
effect is specified, the C flag is set (1) if the result contains an odd number of high (1) bits.
Explanation
TJNZ tests the Value register and jumps to Address if it contains a non-zero number.
When the WZ effect is specified, the Z flag is set (1) if the Value register contains zero.
TJNZ requires a different amount of clock cycles depending on whether or not it has to jump.
If it must jump it takes 4 clock cycles, if no jump occurs it takes 8 clock cycles. Since loops
utilizing TJNZ need to be fast, it is optimized in this way for speed.
TJZ
Instruction: Test value and jump to address if zero.
Explanation
TJZ tests the Value register and jumps to Address if it contains zero.
WAITCNT
Instruction: Pause a cog’s execution temporarily.
• Target (d-field) is the register with the target value to compare against the System
Counter (CNT). When the System Counter has reached Target’s value, Delta is added
to Target.
• Delta (s-field) is the register or a 9-bit literal whose value is added to Target’s value in
preparation for the next WAITCNT instruction. This creates a synchronized delay
window.
Explanation
WAITCNT, “Wait for System Counter,” is one of four wait instructions (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. The WAITCNT
instruction pauses the cog until the global System Counter equals the value in the Target
register, then it adds Delta to Target and execution continues at the next instruction. The
WAITCNT instruction behaves similar to Spin’s WAITCNT command for Synchronized Delays;
see WAITCNT on page 322.
If the WZ effect is specified, the Z flag will be set (1) if the sum of Target and Delta is zero. If
the WC effect is specified, the C flag will set (1) if the sum of Target and Delta resulted in a
32-bit carry (overflow). The result will be written to Target unless the NR effect is specified.
• State (d-field) is the register with the target state(s) to compare against INx ANDed
with Mask.
• Mask (s-field) is the register or a 9-bit literal whose value is bitwise ANDed with INx
before the comparison with State.
Explanation
WAITPEQ, “Wait for Pin(s) to Equal,” is one of four wait instructions (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. The WAITPEQ
instruction pauses the cog until the result of INx ANDed with Mask equals the value in the
State register. INx is either INA or INB depending on the value of the C flag upon execution;
INA if C = 0, INB if C = 1 (the P8X32A is an exception to this rule; it always tests INA).
The WAITPEQ instruction behaves similar to Spin’s WAITPEQ command; see WAITPEQ on page
326.
If the WZ effect is specified, the Z flag will be set (1) if the result of INx ANDed with Mask is
zero.
WAITPNE
Instruction: Pause a cog’s execution until I/O pin(s) do not match designated state(s).
• State (d-field) is the register with the target state(s) to compare against INx ANDed
with Mask.
• Mask (s-field) is the register or a 9-bit literal whose value is bitwise ANDed with INx
before the comparison with State.
Explanation
WAITPNE, “Wait for Pin(s) to Not Equal,” is one of four wait instructions (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. The WAITPNE
instruction pauses the cog until the result of INx ANDed with Mask does not match the value
in the State register. INx is either INA or INB depending on the value of the C flag upon
execution; INA if C = 0, INB if C = 1 (the P8X32A is an exception to this rule; it always tests
INA). The WAITPNE instruction behaves similar to Spin’s WAITPNE command; see WAITPNE on
page 328.
If the WZ effect is specified, the Z flag will be set (1) if the result of INx ANDed with Mask is
zero.
WAITVID
Instruction: Pause a cog’s execution until its Video Generator is available to take pixel data.
• Colors (d-field) is the register with four byte-sized color values, each describing the
four possible colors of the pixel patterns in Pixels.
• Pixels (s-field) is the register or a 9-bit literal whose value is the next 16-pixel by 2-bit
(or 32-pixel by 1-bit) pixel pattern to display.
Explanation
WAITVID, “Wait for Video Generator,” is one of four wait instructions (WAITCNT, WAITPEQ,
WAITPNE, and WAITVID) used to pause execution of a cog until a condition is met. The WAITVID
instruction pauses the cog until its Video Generator hardware is ready for the next pixel data,
then the Video Generator accepts that data (Colors and Pixels) and the cog continues
execution with the next instruction. The WAITVID instruction behaves similar to Spin’s
WAITVID command; see WAITVID on page 329.
If the WZ effect is specified, the Z flag will be set (1) if the Colors and Pixels are equal.
Make sure the cog’s Video Generator module is running before executing a WAITVID,
otherwise the WAITVID instruction will wait forever.
WRBYTE
Instruction: Write a byte to main memory.
• Value (d-field) is the register containing the 8-bit value to write to main memory.
• Address (s-field) is a register or a 9-bit literal whose value is the main memory
address to write to.
Explanation
WRBYTE synchronizes to the Hub and writes the lowest byte in Value to main memory at
Address.
WRBYTE is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
WRLONG
Instruction: Write a long to main memory.
• Value (d-field) is the register containing the 32-bit value to write to main memory.
• Address (s-field) is a register or a 9-bit literal whose value is the main memory
address to write to.
Explanation
WRLONG synchronizes to the Hub and writes the long in Value to main memory at Address.
WRLONG is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. Hub on page 24 for more information.
• Value (d-field) is the register containing the 16-bit value to write to main memory.
• Address (s-field) is a register or a 9-bit literal whose value is the main memory
address to write to.
Explanation
WRWORD synchronizes to the Hub and writes the lowest word in Value to main memory at
Address.
WRWORD is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
depending on the relation between the cog’s hub access window and the instruction’s moment
of execution. See Hub on page 24 for more information.
XOR
Instruction: Bitwise XOR two values.
• Value1 (d-field) is the register containing the value to bitwise XOR with Value2 and is
the destination in which to write the result.
• Value2 (s-field) is a register or a 9-bit literal whose value is bitwise XORed with
Value1.
Explanation
XOR (bitwise exclusive OR) performs a bitwise XOR of the value in Value2 into that of
Value1.
If the WZ effect is specified, the Z flag is set (1) if Value1 XOR Value2 equals zero. If the WC
effect is specified, the C flag is set (1) if the result contains an odd number of high (1) bits.
The result is written to Value1 unless the NR effect is specified.
sin long 0
As with the log and anti-log tables, linear interpolation could be applied to the sine table to
achieve higher resolution.
Index
Defined, 18, 87, 88, 129
_ Initial clock mode, 180
Initial frequency, 177
_CLKFREQ, 131, 132 Starting point, 100
_CLKFREQ (spin), 177–78 Applications and objects, 87
_CLKMODE, 131 Architecture, 13–34
_CLKMODE (spin), 180–82 Archive (menu), 45
_FREE (spin), 218 Arranging multiple objects, 41
_STACK (spin), 307 Array, 107, 165
_XINFREQ, 131, 132 Array index designators, [ ], 313
_XINFREQ (spin), 337–38 Assembly language, 339
ABS, 353
A ABSNEG, 354
ADD, 354–55
Abort ADDABS, 355
Status, 161 ADDS, 356
Trap, 162, 313 ADDSX, 356–57
ABORT (spin), 161–64 ADDX, 357
ABS (asm), 353 AND, 358
ABSNEG (asm), 354 ANDN, 359
Absolute Value ‘||’, 261 Binary operators, 347
Access collisions, 230 CALL, 360–61
ADC, 204 CLKSET, 361
ADD (asm), 354–55 CMP, 362
Add ‘+’, ‘+=’, 255 CMPS, 362–63
ADDABS (asm), 355 CMPSUB, 363
Address ‘@’, 278 CMPSX, 364
Address Plus Symbol ‘@@’, 279 CMPX, 364–65
ADDS (asm), 356 CNT, 397
ADDSX (asm), 356–57 COGID, 365
ADDX (asm), 357 COGINIT, 366–67
Align COGSTOP, 367
Edit mode, 65, 66 Common syntax elements, 348
Text, 66 Conditions, 341, 368–69
Values, 209 Conditions (table), 369
Analog-to-digital conversion, 204 Configuration, 341
AND (asm), 358 CTRA, CTRB, 397
AND (spin), 221 DIRA, DIRB, 397
AND, Bitwise ‘&’, ‘&=’, 269 Directives, 341
AND, Boolean ‘AND’, ‘AND=’, 272 DJNZ, 370
ANDN (asm), 359 Effects, 343, 371
ANSI-encoded, 35 Effects (table), 371
Anti-log table, 420 FIT, 372
Anti-Log Table, 422 Flow control, 343
Application FRQA, FRQB, 397
Propeller Manual v1.0 · Page 425
Index
HUBOP, 373 ROR, 400–401
IF_x (conditions), 368–69 SAR, 401
INA, INB, 397 SHL, 402
JMP, 374 SHR, 402–3
JMPRET, 374–75 Structure, 339
Literal, #, 312 SUB, 403
LOCKCLR, 375 SUBABS, 404
LOCKNEW, 376 SUBS, 404–5
LOCKRET, 376–77 SUBSX, 405
LOCKSET, 377 SUBX, 406
Main memory access, 343 SUMC, 406–7
Master table, 350–51 SUMNC, 407
MAX, 378 SUMNZ, 408
MAXS, 378–79 SUMZ, 408–9
MIN, 379 Syntax definitions, 348
MINS, 380 TEST, 409
MOV, 380–81 TJNZ, 410
MOVD, 381 TJZ, 410–11
MOVI, 382 Unary operators, 346
MOVS, 382–83 VCFG, 397
MUXC, 383 VSCL, 397
MUXNC, 384 WAITCNT, 411
MUXNZ, 384–85 WAITPEQ, 412
MUXZ, 385 WAITPNE, 413
NEG, 386 WAITVID, 414
NEGC, 386–87 WC, 371
NEGNC, 387 WR, 371
NEGNZ, 388 WRBYTE, 414–15
NEGZ, 389 WRLONG, 415
NOP, 389 WRWORD, 416
NR, 371 WZ, 371
Operators, 390–91 XOR, 417
OR, 392 Assignment
ORG, 392–93 Constant ‘=’, 254
OUTA, OUTB, 397 Variable ‘:=’, 255
PAR, 397
PHSA, PHSB, 397
Process control, 341
B
RCL, 393 Bases, numerical, 159
RCR, 394 Binary indicator, %, 312
RDBYTE, 394–95 Binary operators (asm), 347
RDLONG, 395 Binary operators (spin), 157
RDWORD, 396 Bitwise operators
Registers, 397 AND ‘&’, ‘&=’, 269
RES, 398 AND Truth Table (table), 269
RET, 399 Decode ‘|<’, 265
REV, 399 Encode ‘>|’, 266
ROL, 400
Page 426 · Propeller Manual v1.0
Index
NOT ‘!’, 94, 272 C
NOT Truth Table (table), 272
OR ‘|’, ‘|=’, 270 Calculating time, 325
OR Truth Table (table), 270 CALL (asm), 360–61
Reverse ‘><’, ‘><=’, 268 Call Stack, 161, 301, 360
Rotate Left ‘<-’, ‘<-=’, 267 Calls, 104
Rotate Right ‘->’, ‘->=’, 268 Case (find), 50
Shift Left ‘<<’, ‘<<=’, 266 CASE (spin), 171–73
Shift Right ‘>>’, ‘>>=’, 267 Case statement separator, :, 313
XOR ‘^’, ‘^=’, 271 Categorical listing
XOR Truth Table (table), 271 Propeller Assembly language, 341
Block designators, 99, 152 Spin language, 150, 152
Block Diagram (figure), 20–21 Character
Block selection and moving, 68–69 Chart, 58–60
Block Selection and Moving (figure), 69 Chart (figure), 60
Block-group indicators, 74, 95 Definitions, 32
Block-Group Indicators (figure), 74 Interleaving, 33
BOEn (pin), 15 Interleaving (figure), 33
Bookmark Gutter, 63 CHIPVER (spin), 174
Bookmarks, 41, 61, 63 Clear, Post ‘~’, 262
Bookmarks (figure), 63 CLK register, 28
Boolean operators CLK Register Structure (table), 28
AND ‘AND’, ‘AND=’, 272 CLKFREQ (spin), 135, 175–76
Is Equal ‘= =’, ‘= = =’, 275 CLKMODE (spin), 179
Is Equal or Greater ‘=>’, ‘=>=’, 277 CLKSELx (table), 30
Is Equal or Less ‘=<’, ‘=<=’, 277 CLKSET (asm), 361
Is Greater Than ‘>’, ‘>=’, 276 CLKSET (spin), 135, 183
Is Less Than ‘<’, ‘<=’, 276 Clock
Is Not Equal ‘<>’, ‘<>=’, 275 Configuring, 28
NOT ‘NOT’, 274 Frequency, 175, 177, 183
OR ‘OR’, ‘OR=’, 273 Frequency range, 29
Boot Loader, 18, 34 Mode, 28, 31, 179, 180
Boot parameter, 23 Mode Setting Constants (table), 180, 181
Boot up, 26 Panel, 56
Boot up procedure, 18 PLL, 22, 28, 177
Boot-up time, 93 Related timing, 133
Brown Out Enable (pin), 15 Settings, 131
Byte Close (menu), 45
Data declaration, 166 Close All (menu), 45
Memory type, 16, 165 Close button, 51
Reading/writing, 167, 394, 414 CMP (asm), 362
Variable declaration, 166 CMPS (asm), 362–63
BYTE (spin), 165–68 CMPSUB (asm), 363
Byte-aligned, 209 CMPSX (asm), 364
BYTEFILL (spin), 169 CMPX (asm), 364–65
BYTEMOVE (spin), 170 CNT, 23, 94, 305
CNT (asm), 397
M N
Main memory, 30, 97 NEG (asm), 386
Main memory access (asm), 343 Negate ‘-’, 256
Main Memory Map (figure), 31 NEGC (asm), 386–87
Main RAM, 23, 31 NEGNC (asm), 387
Main RAM/ROM (spec), 16 NEGNZ (asm), 388
Main ROM, 23, 32 NEGX, 202, 203
Master clock frequency, 28, 31 NEGZ (asm), 389
Match (find), 49 New (menu), 45
Matching parentheses, 120 NEXT (spin), 246
Math function tables, 420 NOP (asm), 389
Math/Logic Operators (table), 250 NOT, Bitwise ‘!’, 272
MAX (asm), 378 NOT, Boolean ‘NOT’, 274
Maximum, Limit ‘<#’, ‘<#=’, 261 NR (asm), 371
W Z
Wait, 94 Zero-terminated strings, 309
WAITCNT (asm), 411