Here are some draft instructions for porting uLisp to a new platform that it doesn’t currently support.
I’ve made this topic a Wiki - if you’re trying out these instructions feel free to edit it to improve what I’ve written or add information you think is missing (just click the icon at the bottom of the topic).
Requirements
To port uLisp to a new platform it needs to satisfy the following requirements:
- At least 2 Kbytes of RAM.
- At least 32 Kbytes of program memory; probably more for 32-bit platforms.
- A core for the Arduino IDE.
- Support for serial via the Arduino IDE Serial Monitor.
Check that you can upload and run the Blink sketch from File->Examples->01.Basics in the Arduino IDE.
Select the most appropriate starting point
Choose an existing version of uLisp that’s close to the platform that you’re planning to support. Currently the choice is:
-
AVR uLisp: for 16-bit AVR processors. No floating-point support. Images are saved in the on-chip EEPROM.
-
MSP430 uLisp: for 16-bit MSP430 processors. No floating-point support. Images are saved in flash memory or FRAM, as appropriate.
-
ARM uLisp: for 32-bit ARM chips. Floating-point support. Images are saved to an SD card if available, or to DataFlash if available.
-
ESP uLisp: for 32-bit ESP8266 and ESP32 platforms. Images are saved to flash using EEPROM emulation. Includes Wi-Fi extensions.
Specify the workspace
If you don’t do this step you’ll typically get the error:
'WORKSPACESIZE' was not declared in this scope
Locate the section in the uLisp source beginning:
// Workspace
and add a section to the list of supported platforms; for example:
#elif defined(MY_PLATFORM)
#define WORKSPACESIZE 3072 /* Cells (8*bytes) */
#define SYMBOLTABLESIZE 512 /* Bytes */
MY_PLATFORM should be the #define used by the Arduino IDE to identify the platform. I haven’t found a reliable way of discovering this. If in doubt invent a name, and put a:
#define MY_PLATFORM
at the start of the source file.
Edit the line:
#define WORKSPACESIZE 3072
to specify the number of Lisp objects to allocate. On 16-bit platforms each object is 4 bytes, and on 32-bit platforms each object is 8 bytes. Basically the best approach is to give a small value at first, such as 1024, and then increase it until you either get low-memory warnings by the Arduino IDE, or you get erratic behaviour due to not enough stack space.
Edit the line:
#define SYMBOLTABLESIZE 512
to specify the size of the symbol table used for long symbol names (longer than 3 characters, or containing non-alphanumeric characters). 512 is a good size.
At this point you should be able to compile the uLisp source and see what errors you get.
Specify the number of available serial ports
If you don’t do this you will get an error such as:
'serial1read' was not declared in this scope
The simplest thing at this stage is to specify that there is only one serial port; you can add support for Serial1, Serial2, etc later if they are available.
Locate the section in the uLisp source beginning:
// Streams
In the definition of gstreamfun() edit this section as follows:
else if (streamtype == SERIALSTREAM) {
if (address == 0) gfun = gserial;
#if !defined(MY_PLATFORM)
else if (address == 1) gfun = serial1read;
#endif
}
Add a #if to the definition of serial1write() as follows:
#if !defined(MY_PLATFORM)
inline void serial1write (char c) { Serial1.write(c); }
#endif
In the definition of pgstreamfun() edit this section as follows:
else if (streamtype == SERIALSTREAM) {
if (address == 0) pfun = pserial;
#if !defined(MY_PLATFORM)
else if (address == 1) pfun = serial1write;
#endif
}
You should now be able to compile uLisp without errors.
Open the Serial Monitor and check that you get a uLisp prompt. Try typing an input and check that an appropriate response is echoed.
This is the first step; there’s more you’ll need to do to provide support for all uLisp’s features on your platform, but I’ll deal with those on request in further posts.
To check that uLisp is working correctly try some of the benchmarks at: