SwiftX is an interactive development environment (IDE) and cross compiler for developing, debugging, and testing firmware code for microcontrollers and microprocessors. SwiftX is available for ARM, ColdFire, MSP430, AVR, 68HCS08, 68HC12, 68K, 68HC11, and 8051 processor cores. For space and radiation-intensive applications, SwiftX is also available for the rad-hard UT69R000 and RTX2010RH microprocessors.
SwiftX cross compilers are superb for developing embedded systems applications. The SwiftX IDE provides all the finesse and control of bare metal programming via efficient, high-level software tools. Download an evaluation system to test drive.
On This Page
- Rapid development cycle, efficient and robust embedded applications
- Why Use SwiftX?
- SwiftX IDE
- SwiftX Features
- SwiftX Code Optimizer
- Developing Programs with SwiftX
- Embedded Programming Example
- SwiftX Version Comparison
Rapid development cycle, efficient and robust embedded applications
- Wide range of supported microcontrollers
- Interactive software development process
- Incremental code compilation
- Modular software design
- Compact embedded applications
- Optimized for top performance
- Configurable multitasking kernel
When you choose SwiftX, you get the same powerful toolset we use in our own software consulting business. It grew out of our long history of helping embedded systems developers, programmers and engineers get results faster by using the Forth programming language.
Sample application and paper demonstrating the development of a simple embedded Forth application (a Morse code distress signal) developed using SwiftX. The application is ported to three completely different CPU types by changing only the hardware API code. Includes source code.
Why Use SwiftX?
Developers of embedded systems need a programming language that combines high-level operations with the ability to work easily with custom hardware. They need a compiler that adds minimal overhead in run time and memory. To complete a project on schedule, they need to test the software in the target environment, without time-consuming procedures for burning PROMs or downloading.
SwiftX = high-level tools with the control of bare-metal programming. Our software engineering projects rely on the same development tools we offer to our valued customers.
Here is how SwiftX addresses these needs:
- Improves programmer productivity.
SwiftX is highly interactive and includes a fully integrated development environment — so programmers are more productive and have quicker project turnaround.
- Speeds testing of hardware & software.
SwiftX speeds testing because you interact directly with the target hardware and software. You can even use SwiftX to debug your target hardware, because SwiftX lets you read and write registers directly and interactively.
- Minimizes hardware requirements.
SwiftX code is compact — you can pack more functionality into any particular hardware than you ever imagined. The configurable SwiftX kernel and your applications will require far fewer resources than equivalent functionality obtained by using C or proprietary “real-time” kernels.
- Runs fast.
You benefit from very-low-overhead subroutine calls and from the real-time, multitasking features of SwiftOS. And the compact code minimizes paging and other high-overhead memory management strategies. SwiftX lets you incorporate both high-level and assembly definitions. You get the performance you need, while still conserving development time.
- Simplifies software maintenance.
SwiftX code is easy to maintain and modify thanks, in part, to its conciseness, its modularity, and its easy-to-use, on-line documentation. And its Forth foundation means that your application code is virtually an application-specific language — so you can develop your next similar project even more quickly, even on another processor.
Porting SwiftX to new microcontrollers
The structure and modularity of SwiftX’s underlying design make it exceptionally easy to port, even to new MCU architectures — in only a few weeks. If you have new or unusual target hardware, ask us for a quote.
The SwiftX easy-to-use Interactive Development Environment (IDE) provides a common Windows-based user interface across all target systems. It supports efficient, interactive development without external debuggers, emulators, or other expensive, cumbersome tools.
SwiftX brings a whole new dimension to interactive programming. Unlike formal debuggers, where you have to set breakpoints and step through code, in SwiftX you have effortless access to any function in the system, by just supplying parameters and typing its name. You can even type in new functions at the keyboard, and they’re immediately compiled, downloaded, and available for testing.
The SwiftX IDE makes this possible by maintaining an active link to your target device, so you’re actually testing on the target. This is far better than a simulator, as you can directly interact with your I/O as well as your program.
SwiftX cross compilers create an optimized custom, ROMable version of your code for embedding applications. Features include:
- The compile-download-test cycle is extremely short. Compiling an entire kernel takes only a few seconds; even substantial applications can be compiled in under a minute.
- High-level Forth source code is portable across all SwiftX targets; only assembler functions and explicit references to processor-specific features are MCU-dependent.
- You have complete control over kernel configuration and contents. Include or omit features as needed to yield a compact kernel.
- Optimizing compiler and code stripper in SwiftX Pro produces fast, compact target code.
- SwiftX links to familiar programmers’ editors, so with a single command you can find the source for any compiled word, see the location where a compiling error occurred, or display cross-reference information.
SwiftX is designed to give the precise control of bare metal programming via high-level tools that facilitate productivity, efficiency, Agile-friendly iterative development and testing, and producing robust, maintainable code.
Configurable, Multitasking Kernel
Simple executable programs can require only a few hundred bytes of target RAM. That’s because SwiftX kernels are supplied as source code and are fully configurable — you choose which features to include to support your embedded applications.
Low power requirement? One company modified the SwiftX kernel to put their handheld device into “sleep” mode after only one cycle through the multitasker idle loop, thus using 70% less power than an off-the-shelf “real-time” kernel that was supplied only in binary and was not modifiable.
SwiftX systems include SwiftOS, an extremely fast multitasking executive. Features of SwiftOS include:
- Time-critical interrupt service routines link directly to interrupt vectors with no OS overhead, to ensure fast, deterministic response.
- Non-preemptive task-servicing algorithm utilizes time spent waiting on I/O to maximize service to all tasks.
- Complete context switch in only a few machine instructions.
- Semaphores and global variables support intertask synchronization.
|16-bit CPU||32-bit CPU|
|clock & calendar||986||6||722||0|
* representative set of functions
** serial I/O, XTL on the 16-bit CPU
SwiftX supports fully interactive debugging using its Cross-Target Link (XTL) to communicate with the target system. The actual nature of the link depends on the target hardware. Most target harware uses a serial line connected to an onboard serial port; the NXP 68332 and 68HC16 use NXP’s Background Debugging Mode (BDM), and communicate via a parallel port.
The SwiftX XTL provides the following debug functions:
- Display and modify target RAM
- Display target CPU registers
- Download code to target RAM
- Interactive testing of target Forth words
On processors using a BDM or JTAG, very little special software is required in the target to support interactivity. On other processors, the target XTL is implemented in a few hundred bytes of code on the target, along with a target kernel.
Source Code Libraries
SwiftX libraries are provided in source form, with standardized, portable APIs. SwiftX libraries include hundreds of routines, such as:
- integer and fixed-point fraction arithmetic and transcendental functions
- string handling
- clock and calendar
- number conversions
- drivers for serial ports, clock, and other devices
and many others, depending on the target CPU
SwiftX’s single-stepping debugger allows you to step through source compiled from a file. A simple example of its use is the sample program Sstest.f, reproduced below:
[DEBUG \ Starts compiling steppable code : 2X ( n -- n*2) DUP + ; : 3X ( n -- n*3) DUP 2X + ; : 4X ( n -- n*4) DUP 2X SWAP 2X + ; : 5X ( n -- n*5) DUP 2X SWAP 3X + ; DEBUG] \ Stops compiling steppable code
Assuming this source code has been compiled from the file Sstest.f, you may type 4 DEBUG 5X to cause a debug window to appear (“4” is the argument for 5X).
While this debug window is active, you may control it using the buttons at the bottom, which work as follows:
- Step Executes the next word, with no nesting.
- Nest Executes the next word, nesting if it is a call.
- Go ; Executes to the end of the current definition without stopping.
- Run Stops debugging and continues running at (near) full speed.
The current stack is displayed at the bottom of the debug window.
This SwiftX Pro feature strips unused code from your kernel and application, leaving a compact object. It does this by repeating a BUILD, keeping a record of all definitions not called, and then excluding them from the next INCLUDE. This takes several passes, since omitting a definition may remove the only uses of lower-level definitions, which may be omitted on the next pass.
When two successive passes produce an object whose size doesn’t change, it’s finished.
DEBUG can detect whether a BUILD (stripped or otherwise) has been done since SwiftX was loaded. If so, it uses its image (saving the time required to rebuild it).
Since the code stripper will remove anything not called in the current loads, you should avoid stripping the kernel until late in your development cycle, because your application will likely use kernel words that might otherwise be stripped.
The assumption is that you will follow a development path like this:
- Write new code, loaded by debug.f after the SET-DOWNLOAD and before DOWNLOAD-ALL, and test it on top of a full (unstripped) BUILD.
- As code becomes satisfactorily tested, move its INCLUDE statements into the file App.f (see below) where it’s loaded with the kernel (usually only once per session).
- When your application is fully developed and tested, and all moved into App.f, strip that package and use DEBUG> (which now loads nothing) to test the stripped package.
- When that works satisfactorily, replace DEBUG-LOOP in the word GO in App.f with your application startup word (see below).
If you need to make a change in the kernel image being used by DEBUG, you must BUILD it and install it.
Provision for Application Loading
The source file App.f is provided in the target-specific directory for each SwiftX. It contains the definition GO, which is invoked at the appropriate point in the power-up sequence. This file is loaded near the end of Kernel.f, and is intended to load your application source. INCLUDE your application files before the definition GO, and replace the word DEBUG-LOOP (which runs the target XTL for debugging) with your word which performs application initialization and startup.
SwiftX Code Optimizer
The benchmarks in the table below show the performance gains achieved by using the optimizing compiler included in SwiftX Pro. Also shown are some simple examples of source code and the resulting optimized versions.
VARIABLE X1 VARIABLE X2 : TRY ( -- ) X1 @ X2 ! ;
ColdFire object code without optimizer
2250 X1 # A6 -) MOV 2D 3C 20 00 25 62 2256 A6 ) A0 MOV 20 56 2258 A0 ) A6 ) MOV 2C 90 225A X2 # A6 -) MOV 2D 3C 20 00 25 66 2260 A6 )+ A0 MOV 20 5E 2262 A6 )+ A0 ) MOV 20 9E 2264 RTS 4E 75
ColdFire object code with SwiftX optimizer
2250 X1 AB D0 MOV 20 39 20 00 25 62 2256 D0 X2 AB MOV 23 C0 20 00 25 66 225C RTS 4E 75
DIGIT — from the SwiftX kernel source code — converts a binary value to a printable ASCII digit.
: DIGIT ( u -- char) DUP 9 > IF 7 + THEN [CHAR] 0 + ;
ARM Cortex-M object code without optimizer
26A0 LR PUSH B500 26A2 4 R7 SUBS 3F04 26A4 0 R7 R6 STR 603E 26A6 4 R7 SUBS 3F04 26A8 0 R7 R6 STR 603E 26AA 9 R6 MOVS 2609 26AC > BL F7FD FFC0 26B0 0 R6 CMP 2E00 26B2 R6 R7 LDM CF40 26B4 26C0 BEQ D004 26B6 4 R7 SUBS 3F04 26B8 0 R7 R6 STR 603E 26BA 7 R6 MOVS 2607 26BC R0 R7 LDM CF01 26BE R0 R6 R6 ADDS 1836 26C0 4 R7 SUBS 3F04 26C2 0 R7 R6 STR 603E 26C4 30 R6 MOVS 2630 26C6 R0 R7 LDM CF01 26C8 R0 R6 R6 ADDS 1836 26CA PC POP BD00
ARM Cortex-M object code with SwiftX optimizer
26A0 9 R0 MOVS 2009 26A2 R0 R6 CMP 4286 26A4 26A8 BLE DD00 26A6 7 R6 ADDS 3607 26A8 30 R6 ADDS 3630 26AA LR BX 4770
Developing Programs with SwiftX
SwiftX embedded systems development is controlled from a command window using standard Windows toolbar buttons and menus. Here embedded systems developers control the process of compiling software, downloading it into target hardware, and testing it interactively. You can use any standard Windows programmer’s editor to edit your applications’ source files, and easily load and test them from SwiftX.
SwiftX software compilers support interactive testing on the actual target, not on a simulator, via a “cross target link” (XTL). Using the actual target means you have direct access to all of your target hardware, which is very important for development of embedded applications that control certain equipment and handheld devices.
The SwiftX package includes a sample application — emulating a handheld calculating device — that you can study, run, and modify in order to become comfortable with SwiftX programming quickly.
- Configure a memory map for your target device.
- Modify or add any device or I/O drivers that are specific to the target.
- Adapt the example startup code to initialize your target hardware and software.
General SwiftX development procedures and functions include:
Target memory may be mapped for program memory, initialized data space, and uninitialized data space. You can define multiple sections of each type, specifying the optimal location and size for your target hardware. You may, for example, place frequently accessed variables in on-chip RAM for maximum speed, while leaving larger arrays in external, or even paged, RAM.
It is very easy to develop custom I/O drivers in SwiftX. XTL communication with the target lets you examine and even modify I/O registers directly, to test the device’s functionality. Typically, drivers are quite small, and are made up of several related simple definitions (e.g., one to read and one to write), which can also be tested interactively. Several examples (e.g., serial I/O, clock) are provided with your SwiftX system. To see how easily you can control digital devices such as motors and switches, look at the Washing Machine example.
SwiftOS makes interrupt handling simple. The strategy is:
- Perform only the most time-critical actions at interrupt time.
- Notify the task responsible for the interrupting device that the interrupt has occurred.
- Defer complex logic to high-level routines executed by that task.
Notification may take the form of setting a flag, incrementing or decrementing a counter, or modifying the task’s status so it will become active at the next opportunity in the multitasker cycle.
The basic, high level code form of an interrupt handler is:
LABEL <name> <code instructions> <name> <dev#> INTERRUPT
where LABEL starts the definition of the routine, which is called name; the code instructions perform the necessary work of the routine; dev# is the device code or interrupt vector to which the routine will respond, and INTERRUPT is a special code-ending macro that assembles the appropriate return-from-interrupt instruction and attaches the address of name to the interrupt vector. When an interrupt occurs, it will be vectored directly to the code at name with no overhead imposed by SwiftOS.
Customizing Your Kernel
SwiftX includes the complete, high level source code for your target kernel, so you can modify it in any way that suits your needs: add, delete, or change anything. You also have complete control over your ability to map memory. With SwiftX Pro, you can even modify the assembler (e.g., to add instructions that only appear in certain chip variants). By omitting unused functions, you can reduce the size of your program to fit in even very small target hardware. This can be done manually in SwiftX, or automatically using the “stripper” feature in SwiftX Pro.
During development, it is convenient to be able to test your embedded programs in RAM. SwiftX’s flexible memory configuration makes it easy to, for example, map more RAM during development than you may have in the final product, or to substitute RAM chips for PROMs during development. On many targets, it is possible to run your kernel code in flash or EEPROM, and to test your embedded applications’ code in RAM; as code is validated, it may be added to the code loaded with the kernel.
If you have limited program RAM, a good strategy might be to start with a simple SwiftX kernel in PROM. You can interactively test some application code in RAM and, as more of it becomes stable, add it to the kernel in PROM.
SwiftX writes its object files in whatever format is most appropriate for burning flash or PROMs on a particular platform, either HEX records, S-records, or binary files. Wherever possible, SwiftX includes its own download utility to simplify development procedures, however these standard format files may also be used by any PROM-burning utility.
Embedded Programming Example
The process of cross compiling a program in SwiftX is consistent with the recommended practices of top-down design and bottom-up coding and testing. However, Forth adds another element: extreme modularity. You don’t write page after page of code and then try to figure out why it doesn’t work; instead, you write a few brief definitions and exercise them, one by one.
As one of many examples, suppose we are designing a washing machine. The high level definition might be:
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
The colon indicates that a new word is being defined; following it is the name of the new word, WASHER. The remainder are the words that comprise this definition. Finally, the definition is terminated by a semi-colon.
Typically, we design the highest-level routines first. This approach leads to conceptually correct solutions with a minimum of effort. But in Forth — SwitfX’s native “compiler compiler” language — words must be compiled before they can be referenced, so code listings begin with the most primitive definitions and end with the highest-level words.
A complete, annotated listing of the washing machine program is given below. Items in parentheses or following a backslash (\) are comments. The first few lines define a hardware port address (in this case, on a 68HC12) and six bit masks used to access individual bits on that port. Subsequent lines define application words that do the work.
The source code in this example is nearly self-documenting; the comments identify groups of words and show the parameters being passed to certain words. When reading,
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
it is obvious what RINSE does. To determine how it does it, you read:
: RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
When you wonder how FILL-TUB works, you find:
: FILL-TUB ( -- ) FAUCETS ON TILL-FULL FAUCETS OFF ;
Reading further, one finds that FAUCETS is a mask specifying the bit of the port that controls the faucet, while ON is a word that turns on that bit.
Even from this simple example, it may be clear that Forth is not so much a language as a tool for building application-oriented command sets. The definition of WASHER is based not on low-level Forth words, but on words with names like SPIN and RINSE that make sense in the context of the application.
When developing this embedded program, you would follow your top-down logic, as described above. But when the time comes to test the application code example using SwiftX’s Cross-Target Link (XTL), you will see the real convenience of Forth’s interactivity.
If your hardware is available, your first step would be to see if it works. Even without the code in the file, you could read and write to target hardware registers by typing phrases such as:
HEX PORT C@ .
The word C@ fetches a character (byte) from the address specified by PORT. This would read port address 01 and display its current bit values. The similar phrase PORT C! (used in ON and OFF) stores a value in the address.
You could also type:
2 ON 2 OFF
to see if the clutch, controlled by the bit masked by 2, engages and disengages. If the hardware is unavailable, you might temporarily re-define PORT as a variable you can read and write, and so test the rest of the logic.
You can load your source code file using the command INCLUDE , whereupon all functions defined in the specified file are parsed and available for testing. You can further exercise your I/O by typing high level, application-appropriate phrases such as:
…to see what happens. Then you can exercise your low-level words, such as:
…and so on, until your highest-level words are tested.
As you work, you can use any additional embedded systems programmer aids provided by SwiftX. You can easily change your embedding code and re-load it. But your main ally is the intrinsically interactive nature of Forth itself, the programming language with which SwiftX cross compilers are generated.
Annotated example source code
Parentheses and backslashes denote comments. Listings begin with primitive functions.
( Washing Machine Embedded Application ) \ Port assignments 01 CONSTANT PORT \ bit-mask name bit-mask name 1 CONSTANT MOTOR 8 CONSTANT FAUCETS 2 CONSTANT CLUTCH 16 CONSTANT DETERGENT 4 CONSTANT PUMP 32 CONSTANT LEVEL
A colon begins a new definition.
\ Device control : ON ( mask -- ) PORT C@ OR PORT C! ; : OFF ( mask -- ) INVERT PORT C@ AND PORT C! ;
Definitions can contain generic SwiftX words and any others you’ve defined…
\Timing functions : SECONDS ( n -- ) 0 ?DO 1000 MS LOOP ; : MINUTES ( n -- ) 60 * SECONDS ; : TILL-FULL ( -- ) \ Wait till level switch is on BEGIN PORT C@ LEVEL AND UNTIL ;
…so, application-specific functions are defined in terms of previous definitions…
\ Washing machine functions : ADD ( port -- ) DUP ON 10 SECONDS OFF ; : DRAIN ( -- ) PUMP ON 3 MINUTES ; : AGITATE ( -- ) MOTOR ON 10 MINUTES MOTOR OFF ; : SPIN ( -- ) CLUTCH ON MOTOR ON 5 MINUTES MOTOR OFF CLUTCH OFF PUMP OFF ; : FILL-TUB ( -- ) FAUCETS ON TILL-FULL FAUCETS OFF ; \ Wash cycles : WASH ( -- ) FILL-TUB DETERGENT ADD AGITATE DRAIN ; : RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
…until you reach the main application definition.
\ Top-level control : WASHER ( -- ) WASH SPIN RINSE SPIN ;
|Washing Machine program||297||0|
The final program (with the XTL and unused functions removed from the kernel) is quite small, as you can see in the table. The RAM figure includes stack space and system variables. Stack requirements vary when cross compiling, depending on the processor; for example, an 8051 would require less than the amounts shown here. With most microcontrollers, the compiled code can reside in the target’s onboard memory.
SwiftX Version Comparison
- SwiftX Evaluation allows you to experience the look and feel of the SwiftX environment. The evaluation version is constrained to compile into limited target object size.
- SwiftX Lite is a low-cost, entry-level system that is intended for hobbyists or individual engineers. It provides a basic toolset, the SwiftX host development environment, and target source code. SwiftX Lite is a good way to learn about the SwiftX programming approach or to get a quick start on your embedded systems project. You can always upgrade to SwiftX Pro, and your code will be fully portable — but smaller and faster, thanks to SwiftX Pro’s optimizing compiler.
- SwiftX Pro adds project management tools, an optimizing compiler, code stripper, optional target-resident interpreter and compiler, and complete source code for the cross compiler as well as the target. SwiftX Pro is intended for commercial and professional application development.
The table below will help you compare the features of SwiftX and SwiftX Pro cross compilers, along with our free evaluation versions of SwiftX.
|Evaluation||SwiftX Lite||SwiftX Pro|
|source code for cross compiler||N||N||Y|
|source code for target||Y||Y||Y|
|target-resident interpreter/compiler||N||N||Y (most)|
|support period||none||1 year||1 year|