MacroExpressions Products: C-SLang

Home Products Services Download Contact us
General introduction to MacroExpressions ^
<You are here>
Consulting, products customization, custom development C-Slang, Unimal and Snob are available for evaluation Email, telephone and fax numbers
Click on a button below to go to a related page
Table of contents
What is C-SLang?
What's new in 2.0?
Benefits of C-SLang
How it's implemented
Compiler compatibility
Is it hard?
Any debugging aids?
Convincing example
C-SLang in toolchain
Credits and acknowledgments

What is C-SLang? ( Contents)

(Initial intro is here. For a brief executive summary click here).
Complete online manual (large) is available in a new window.

A note on compiler compatibility is found below.

In short, 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 SVIRM.

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 C-SLang source.

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 platform.

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? ( Contents)

(Those unfamiliar with C-SLang can safely skip this)
Version 2.0 is a major rewrite. Here is the list of changes:
  1. C-SLang script representation is now independent of luck with the compiler; it is conforming to C standard.
  2. Accordingly, the syntax of a script header has slightly changed.
  3. Repeat LoadA and Repeat LoadX operations now do useful things.
  4. StoreAExt instruction added.
  5. CallNative instructions are no longer supported since their functionality is covered by virtual physical input/output instructions.
  6. 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 provided.
  7. 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.
  8. Virtual machine now performs runtime array boundaries check.
  9. Debug interface is added via single step and breakpoint facilities.
  10. Script always executes starting from the first registered function.

What is in C-SLang for me? ( Contents)

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 ( Contents)

Mass-produced electronic 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.

Re-testing the 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 advance.

Detecting elusive 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?

Compacting slow 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 ( Contents)

In 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? ( Contents)

Its design is optimized for code density and is motivated by an unusual company: 8-bit assemblers, FORTRAN and Java, and even some COBOL.

C-SLang virtual machine ( Contents)

C-SLang virtual machine has two registers A and X (for accumulator and index) and five distinct address spaces:

  • input variables
  • output variables
  • temporary variables
  • virtual physical inputs
  • virtual physical outputs.

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.

How to use C-SLang scripts ( Contents)

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 application.

To run bytecode from within the application, you simply link the script as part of the application; that's all.

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 ( Contents)

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 mode.)

Here is a quick test: If your compiler successfully compiles the file compileme.c, it is OK for C-SLang.

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 bytecode.

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 standard-compliant compiler.

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? ( Contents)

C-SLang (starting with ver. 2.0) provides API calls to single-step through the script or to set any number of breakpoints.

Comprehensive runtime error checking should help in debugging, too. And, of course, you can use a "virtual physical output" function to print out intermediate results.

Additionally, since 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 debugging.

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? ( Contents)

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 code.

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.