What is C-SLang? (
(Initial intro is
here. For a brief executive summary click
(large) is available in a new window.
A note on compiler compatibility is found below.
C-SLang is a very
simple language for software components requiring the highest code density
possible but which have rather relaxed execution time requirements. Please, see
the next section for some examples of such components. For a more in-depth
coverage of a particular application - diagnostic modules for
resource-constrained embedded systems - please, check out the white paper
available in pdf or html.
A unique feature of
C-SLang is that in fact the source code is a sequence
of unusually looking C constructs. Therefore, C-SLang source code is
also C source code, and it is "compiled" by any ISO/ANSI C compiler.
These constant data
represent C-SLang bytecode, which is executed by a tiny interpreter
called C-SLang virtual machine, or
C-SLang bytecode can
be exported in a stand-alone format. The resulting bytecode can be downloaded to and executed in a completely
different target machine than the one used to create and debug the
The latter is worth
repeating: since bytecode is platform-independent, the collection of C-SLang
routines remains a reusable asset even if you change your computing
A subtle additional
benefit of using C-SLang downloadable code: there are odd microcontrollers that
do not execute code from certain areas of RAM. Since C-SLang bytecode is
actually data, this behavior does not pose any problem.
What's new in C-SLang 2.0? (
(Those unfamiliar with
C-SLang can safely skip this)
2.0 is a major rewrite. Here is the list of changes:
- C-SLang script
representation is now independent of luck with the compiler; it is conforming
to C standard.
- Accordingly, the syntax
of a script header has slightly changed.
- Repeat LoadA and Repeat
LoadX operations now do useful things.
- StoreAExt instruction
- CallNative instructions
are no longer supported since their functionality is covered by virtual
physical input/output instructions.
- Integral C types of
input, temporary and output variables, as well as of registers, are now
supplied by the user to better match the platform. A template header is
- C-SLang virtual machine
no longer owns the run control structure; it is passed as an argument. Thus,
the virtual machine is reentrant and, in particular, thread-safe.
- Virtual machine now
performs runtime array boundaries check.
- Debug interface is
added via single step and breakpoint facilities.
- Script always executes
starting from the first registered function.
in C-SLang for me? (
Presented below are
several categories of applications where you can really benefit from using
C-SLang whether as linked-in
or as downloadable bytecode. Most of these applications are in embedded
systems, where the code size is often a bottleneck.
Production Testing (
control units should include support for plant testing procedures and quality
control. The deeper and more sophisticated the testing is, the more ECU
software overhead is required. Not only does it drive the development costs up,
but also increases the ROM requirements, which too, eventually translates to
the unit cost. Besides, additional software potentially introduces additional
errors, which in the best-case scenario increase time to market.
failed units ( Contents)
Even more sophisticated
testing is required for manufacturing quality assurance of ECUs that failed the
production test or those failed in the field and returned by the dissatisfied
customer. Complex production ECUs need software support for identifying the
failed hardware component nowadays rarely accessible with the oscilloscope.
Potentially, each hardware component requires a specially designed test code
that goes beyond basic "pass/fail" level. Alas, these test routines tend to be
large, and it is unrealistic to have them in the ECU's ROM. Moreover, in many
cases these routines have explorative nature and simply cannot be written in
bugs ( Contents)
Everything is just fine
on the developer's bench, but something odd happens in the field under rare and
unpredictable circumstances. Is it a software bug? Or maybe, a hardware
problem? Is the product recall looming? If you can capture the traces of inputs
and outputs, you can play them back on the bench… but how to peek inside
the production ECU to see what causes the failure?
code ( Contents)
Regardless of how
time-critical your application is, it is likely to have components that just
don't need warping speed: consider, for instance, output to an LCD display or
polling a pushbutton. For such a component, the goal is to save as much memory
as possible by trading execution time for RAM and ROM. In this case,
interpreted code is a justified choice.
n:1 standby controller (
some control systems applications, limited redundancy is provided in order to
turn the system crash into a well-controlled "soft landing" and/or to perform
vital system functions in case of a component failure. If an n:1 standby
controller is used for this purpose, the problem is that it is rather big and
expensive (to have at least part of the intelligence of every controller it can
replace). It can be beneficial if the code in the standby controller is stored
in a compact form and interpreted in real time. Better yet, if the dying
controller or its proxy can emit the code to execute, then the standby doesn't
need much intelligence at all: instead, each primary controller knows what the
standby controller must do.
How is C-SLang implemented? (
Its design is optimized for code density and is
motivated by an unusual company: 8-bit assemblers, FORTRAN and Java, and even
machine ( Contents)
C-SLang virtual machine
has two registers A and X (for accumulator and index) and five
distinct address spaces:
- input variables
- virtual physical
- virtual physical
A C-SLang script (code)
may but does not have to use any or all of them.
Virtual physical I/O
require, if used, application-specific functions implementing hardware
abstraction layer. Via these functions, C-SLang interfaces with external world.
In fact, what those
functions do is beyond C-SLang scope, and they can be designed to do whatever
native processing is required. Therefore virtual I/O functions are the only
interface to the target platform, and C-SLang, starting with version 2.0,
doesn't support a (redundant) CallNative instruction.
To prepare a C-SLang
script for use, you need to decide whether it is to run from within your
application or as a downloadable program. In both cases you will need to link
C-SLang virtual machine (a.k.a. bytecode interpreter) together with your
To run bytecode from
within the application, you simply link the script as part of the application;
To run bytecode as a
downloadable program, you need to export your script as stand-alone bytecode.
Then you can store this bytecode as a disk file, or in ROM of some other
controller, or in any way your particular circumstances demand. A helper
utility to export a byte is included in the distribution.
Executing a C-SLang
script is a two-step procedure.
First, you initialize
C-SLang virtual machine by telling it what script to run and where the five
address spaces are mapped. Second, you call the virtual machine. This causes
the script to be executed starting with the first function and until this
function returns or until a runtime error is detected. Of course, if you need
to run the same script repeatedly with the same address spaces, you need not
initialize the virtual machine again.
Compiler compatibility (
C-SLang virtual machine is compiled by pretty
much any compiler that knows how to spell "C".
C-SLang scripts do require an ISO/ANSI compatible C
compiler. (In particular, a C++ compiler will not do unless it has a C
Here is a quick test: If your compiler successfully
compiles the file compileme.c, it is OK for
It turns out there are major compiler vendors in the
embedded world whose even newest products are not fully standard-compliant. Or
you might be stuck with an older non-compliant compiler for some reason. What
are the options in this case?
First, you may choose to use a different compiler
(say, for your desktop platform) to compile and debug C-SLang scripts. When you
have your script ready, export it to a file as you normally would. If you meant
to have it linked in though, you'll need to convert your exported file into a C
source containing an equivalent const unsigned char array of bytes. That you
can compile and link, and pass to the virtual machine as an exported
The second option is to use the Unimal add-on for
C-SLang. This option sacrifices ideological purity of C-SLang ("no additional
tools required") in order to accommodate a non-compliant C compiler: You will
need Unimal. A description of motivation, sampling of
compilers, and, of course, the how-to are in this
document. The Unimal header is available here.
Of course, the third option is to get yourself a
Is it hard to write good C-SLang code? ( Contents)
Like in most languages,
implementing an algorithm does take certain effort. However, C-SLang is
optimized for the intended tasks, and it is pretty difficult to write really bad code. That said, there is
usually more than one way of implementing an algorithm, and it is the art of
programming to come up with the most size-efficient solution. To assist with
the task, the length of each C-SLang "instruction" is documented.
Any debugging aids? (
C-SLang (starting with
ver. 2.0) provides API calls to single-step through the script or to set any
number of breakpoints.
error checking should help in debugging, too. And, of course, you can use a
"virtual physical output" function to print out intermediate
C-SLang source is in fact platform-independent C source, you can use a C source
code debugger of your choice to debug C-SLang code. Since the C-SLang virtual
machine comes with the full source code, you can step through interpretation of
each C-SLang instruction and do all other debugging tricks available for C
How about a convincing example? ( Contents)
A representative example
of C-SLang application is included in the documentation available for
download along with the evaluation version
of C-SLang. It is too lengthy to be reproduced here verbatim, but a brief
description of it follows.
The example implements
simplified processing of SAE J2178 automotive
diagnostic requests like "Report diagnostic trouble codes by status" (five
types of requests total). The implementation of the frame message processing,
complete with negative response for invalid format and for unsupported
"commands," takes less than 200 bytes. This would be a remarkable result even
for an 8-bit assembler code.
How do I include C-SLang in my toolchain?
If your C (or C/C++)
compiler is already part of your toolchain, there is nothing more to include
(otherwise, do include a C compiler). Note that SVIRM (C-SLang virtual machine)
and a few helper functions are written in C and supplied as source
To make C-SLang available
to your project, simply include C-SLang header files in the C-SLang source
files (which, recall, are C source files) and link together with SVIRM and
necessary helpers. (Make sure you compile C-SLang as C, not as C++!) Please,
consult with the documentation for greater details.
If you have any difficulties
integrating C-SLang, please, contact us and we will
be happy to help.