Table of Contents
- Getting Started
- Configuring LambdaDelta
- Using LambdaDelta
LambdaDelta is an emulator of the LMI Lambda Lisp Machine. Its goal is to simulate the hardware sufficiently to run original microcode and binaries unmodified, with performance and capability comparable to the original hardware.
LambdaDelta is written in C. It is intended to be portable to any reasonably Unix-like operating system, but is developed primarily on GNU/Linux. The initial versions will most likely fail to compile elsewhere, but attempts will be made to rectify this as soon as practical.
SDL Version 1 or 2 is used for console IO, the GNU/Linux tuntap driver or Berkeley Packet Filter is used for network IO, and standard Unix file operations are used for disk and tape IO. LambdaDelta includes code from the Fake86 project by Mike Chambers in its SDU implementation.
LambdaDelta is licensed under the GNU GPL Version 2 or later at your option. Please see the file COPYING for details.
About the Lambda
The LMI Lambda is a NuBus-based machine consisting of at least one Lambda processor, a System Diagnostic Unit, and various NuBus and Multibus peripherals. The System Diagnostic Unit has an Intel 8088 processor, and is responsible for bootstrapping the Lambda processor. The Lambda processor is made up of four cards in a specially wired area of the NuBus backplane. The standard Multibus peripherals are a 3Com ethernet interface, an Interphase SMD disk controller, a Tapemaster 9-track tape controller, and a Quarterback QIC tape controller (not emulated). The SDU software mediates sharing of Multibus peripherals. The SDU hardware provides a DMA path between Multibus space and NuBus space with mapping hardware for routing pages between targets on both busses.
The NuBus peripherals are memory and the VCMEM console controller. There must be one VCMEM for each Lambda processor. The standard configuration has one pair. An optional configuration called LAMBDA-2x2 has two pairs. This enables two simultaneous and separate Lisp environments to share one backplane, memory, disk, and network interface. The result was a considerable cost savings over buying a second machine. The 2x2 machine was also used for operating system development.
There was also an optional 68000-based Unix processor which could run V7 or SVR4. No attempt was made to emulate this. A configuration with a Unix processor was given the suffix "plus", making a "LAMBDA-PLUS" (or "LAMBDA+") a single-user Lambda with a Unix processor and a "LAMBDA-2X2-PLUS" a two-user Lambda with a Unix processor.
Questions, ideas, problems, solutions, praise, complaints, or baseless accusations may be directed to the LispM mailing list on tunes.org. See http://lists.tunes.org/mailman/listinfo/lispm/ for more information.
All contributors to this project are listed in the AUTHORS file.
LambdaDelta requires a set of ROM images from a physical Lambda, and either a disk image of an installed system or images of the installation and source tapes. At the time of release, these items are available from Bitsavers. See http://www.bitsavers.org/ for more information.
Bogodyne ZetaLisp System 500.0 Release 1 can be found at https://www.bogodyne.com/download/download-zetalisp/
LambdaDelta uses the GNU auto* tools for configuration and
compilation. Most features and libraries should be configured
automatically when the
configure script is run.
To generate the configure script from a git checkout, the usual recipe
aclocal ; autoheader ; autoconf ; automake --add-missing. Your
platform may require different invocation(s) of these programs.
If the generated configure script fails, try
autoreconf -i and
re-run it. (See dseagrav/ld#6 for the issue.)
If your system has both SDL1 and SDL2, you will be required to
explicitly disable the one you do not want (use --
SDL1 seems to perform better over remote X11 connections, but SDL2 has
better performance when running locally.
If you wish to emulate the optional 2x2 configuration, run configure
with the option
If you are in possession of a physical Lambda keyboard and/or mouse,
you may enable the use of these with the options
--enable-config-physms. You will need
to provide serial interface hardware as required to communicate with
After compilation, run-time options are controlled by a configuration file. If you have the YAML library installed (and configure found it), it will use YAML configuration. Otherwise, it will use the old configuration file.
Note: If you do not have libyaml on your system (or do not wish to install it), please see Old Configuration File for the legacy configuration system..
This is the new configuration method that is intended to be used going
forward. The YAML configuration file is named
lam.yml and is
searched for in the following places, in order:
- The directory specified in
SYSCONFDIRif it was defined during build.
- The user's home directory, as determined by:
$HOMEenvironment variable, or if that is not defined:
- If we are root and were run by sudo, from the sudoer's passwd entry.
- If we are root and were not run by sudo, root's passwd entry.
- If we are not root, the user's passwd entry.
- The current working directory.
Any or all of these locations are valid; Configuration items in later files supersede those specified in earlier files.
You may also specify a configuration file of any name on the command
line by using the
-c argument. This file, if provided, is loaded
Single YAML key/value pairs may also be specified on the command line
by specifying them in the form
--section-key value. For example,
--log-ALL 10 will enable maximum logging of all types.
A full description of the YAML configuration file is beyond the scope of this document; See the "lam.yml" file in the examples directory.
Old Configuration File
Note: This file is provided for people who do not have libyaml on their system and wish to configure LambdaDelta without that dependency. However, it will not continue to be supported.
The old configuration file is named "ld.conf" and must be in the current working directory. An example configuration is provided in the examples directory. Each line of the configuration file has a keyword followed by a number of parameters. The following are the supported keywords and their parameters:
Causes the ethernet interface to be bound to the specified interface. The default is "ldtap".
For tuntap, this is the name of the tuntap device to use.
For BPF, this is the interface the BPF interface will be bound to. As this is used for the passing of raw frames, it must be a wired Ethernet interface (or something emulating one) - A wireless interface will not work.
Sets the MAC address used by the Lambda. The default is 00:02:9C:55:89:C6.
This must be unique on your LAN, so do not make it the same as the host! It is written in the canonical colon-separated hex format.
You can also specify LAA (case-insensitive) to generate a Locally Administered Address, which is saved persistently per interface in the file $IFNAME.LAA.
disk N FNAME
Sets the image file for disk unit N. The default is that unit 0 is disks/disk.img and all other units are absent.
The given FNAME must exist. The geometry of the disk is determined by settings in the SDU.
Sets the position of the SDU's rotary switch. The default is 0.
N is a single hex digit 0-F. Position 0 is used for initial software installation or recovery. Position 1 is the standard configuration. The other positions operate as determined by the SDU configuration. If the position is not 1, LambdaDelta will wait for a telnet connection on port 3637 after startup. This simulates a terminal connected to the SDU's serial port.
Sets the operation mode of the mouse emulation. The default is 1.
In mode 0, the mouse protocol is emulated directly using SDL relative mouse movement data. The lisp mouse pointer moves independently of the host mouse pointer, and movement may be difficult or unpredictable on some platforms. In mode 1, the position of the host's mouse pointer is written directly into the Lambda processor's memory, causing the mouse pointer to remain in sync with the host but requiring knowledge of the offsets at which the pointer data resides. For more information, see the usage instructions later in this document.
Sets the memory offsets used for mouse operation mode 1. The defaults are 0156, 0157, and 0170 for both processors.
The 0 or 1 indicates Lambda 0 or Lambda 1. N is an octal offset into A-memory. The offsets are for the X coordinate, the Y coordinate, and the mouse updation flag. You should only have to modify this if you modify the microcode.
Sets the pixel values used for on and off. The default pixel values are 0xFFFFFFFF for on and 0x00000000 for off.
The standard pixel format is AARRGGBB where AA is Alpha, RR is Red, GG is Green, BB is Blue.
Sets the framerate used for video output or user input. The default values are 60 input frames per second and 10 video frames per second.
These are updated in the decisecond loop, so values less than ten will not work as expected, and will be set to ten.
Note that the video frame rate does not affect updation of the title bar, only the rate at which the SDL framebuffer is refreshed.
Enables or disables handling of the platform-specific SDL_QUIT event. The default is enabled.
(Alt-F4,Command-Q,etc.) STATE is one of on,off,yes,no,true,or false.
map_key HV LV
Maps host key HV to Lambda key LV. The default keymap is described later in this document.
HV is a decimal SDL key code, LV is an octal Lambda key code. See the KEYCODES file in the doc directory for a list of Lambda key codes. See the SDL documentation for your SDL version to find the SDL key codes. SDL1 codes start with SDLK_ and SDL2 codes start with SDL_SCANCODE_.
While the program is running, the window title bar has the following form:
LambdaDelta: VC N | Tape: FNAME | STATUS | DT X
N is the number of the active console, either 0 or 1. N is always
zero when the 2x2 configuration is not in use.
FNAME is the name of
the active tape image file.
STATUS is a string describing the state
of the Lambda processor associated with this console. The strings
have the following meanings:
|Cold Halted||The processor has been powered on and has no state.|
|Cold Running||The halt flag is clear but the state is unknown.|
|Cold Booting||The bootstrap is running.|
|Lisp Boot Halted||The processor halted while Lisp was initializing. (This is an error condition.)|
|Lisp Booting||Lisp is initializing or warm booting.|
|Running||Lisp is running.|
|Halted||Lisp has stopped running. The processor has valid state. If you did not halt lisp, this is an error condition.|
After the status string is the time offset. X is a number in deciseconds which indicates how far apart real time and the emulator's time are. The emulator will try to hold this number at 0, but if your computer is not fast enough to run the emulator in real time this number will become negative and decrease further as the times diverge. If the number becomes positive and increases, the throttle is not operating properly. This is a bug which should be reported.
The following keys control emulator functions are cannot be remapped:
F9 switches the active console if the 2x2 configuration is enabled.
If the standard configuration is in use, F9 may be remapped.
F10 changes mouse operation according to the configured mouse mode.
In mode 0, F10 toggles capture and release of the mouse pointer. Clicking inside the LambdaDelta window while the mouse is not captured will recapture it.
In mode 1, F10 toggles visibility of the host mouse pointer.
F11 simulates the "return to newboot" keyboard chord, which terminates Lisp and recalls the Newboot interface.
Limitations of the keyboard emulation make typing the actual chord fail, so this directly sends the expected sequence of bytes to make things happen.
F12 causes the active tape image file to rotate to the next file in ASCIIbetical order.
Pressing control and F12 at the same time causes the emulator to dump its state into a bunch of .DUMP files. These files are human-readable but not necessarily human-understandable. (It is our understanding that whether or not the developers are classified as human is a subject of ongoing debate.)
All other keys on the keyboard may be remapped using the map_key option described above. The standard mapping preserves the printed key label of the standard typewriter keys. The other keys are mapped as follows:
|HOST KEY||LISPM KEY||NOTES|
|[||(||[ is the shift state, ( is unshifted|
|]||)||] is the shift state, ) is unshifted|
|RIGHT CTRL||LEFT GREEK|
|RIGHT ALT||LEFT SUPER|
|LEFT ALT||LEFT META|
|RIGHT FLAG||RIGHT SUPER||Does not always work on some platforms|
|LEFT FLAG||LEFT SUPER||Does not always work on some platforms|
The default keymap is still under development and is subject to change. Feel free to make suggestions or comments.
Preparing ROM Images
The ROM images go in the "roms" subdirectory. The necessary files are:
The SDU's 8088 program ROM. 64K, merged from two chips on the board. Bitsavers has one with an MD5 checksum of
The VCMEM's nubus-space configuration ROM. 2K. This contains 8088 program code that will be run by the SDU. The one on Bitsavers has an MD5 checksum of
These can be found in zip files on the PDFs side of Bitsavers.
fossil sync -u fossil uv export roms/VCMEM.ROM roms/VCMEM.ROM Copy of VC_MEM/U43_2516_2242843-0001_0856TI200038.BIN from VC_MEM.ZIP. fossil uv export roms/SDU.ROM roms/SDU.ROM Copy of SDU_15165-0003/combined.BIN from SDU_15165-0003.ZIP.
Microcode Symbol Files
In the lisp source tree there are files named
ulambda.lmc-sym which correspond to the Lambda bootstrap code
downloaded by the SDU and the Lisp microcode. Place these in the
LambdaDelta directory to provide symbols for debugging. These are
fossil uv export ulambda.lmc-sym ulambda.lmc-sym fossil uv export bootstrap.lam-uload bootstrap.lam-uload
Since installation takes a long time, there is a prepared disk image. Do the above two steps (ROM and microcode), followed by:
fossil uv export LAMA-lam.yml lam.yml fossil uv export LAMA-CMOS.RAM CMOS.RAM fossil uv export LAMA-disk.img.xz disks/LAMA-disk.img.xz xz -dc disks/LAMA-disk.img.xz > disks/disk.img
You should be able to start your Lambda machine, and have a usable system.
N.B. If you configured things in a older version of LambdaDelta it is
important to refresh the SDU configuration, start ld and issue the
config command. When asked if you wish to change anything, answer
yes. At the
cmd: prompt, type
x, boot as usual.
Backup the disk and CMOS file for later.
Installing a New Machine
Prepare your config file, ROM images, tape images, and create the disk image file. Ensure the SDU switch setting is zero in your configuration.
fossil uv export tapes/00_install.tap tapes/00_install.tap fossil uv export tapes/02_system.tap tapes/02_system.tap fossil uv export disk-empty.img.xz disks/disk-empty.img.xz xz -dc disks/disk-empty.img.xz > disks/disk.img cat << EOF > lam.yml sdu: switch: 0 EOF
Start the emulator. Telnet to port 3637 on the host. The emulator should start, and you should have a SDU prompt in your telnet session.
Ignore the graphical console for the now - It is inoperative until the SDU firmware partition is loaded and the CMOS contents are valid.
On GNU/Linux systems, to use the Ethernet interface you will need to add a tun interface.
In another console:
telnet localhost 3637
initand push enter to initialize the busses and SDU. The SDU will reboot.
Ensure the install tape is the active tape.
Push F12 to switch tapes; for the Bitsavers 00_install.tap tape to work one needs to use ld 0.98.1.
Give the SDU command
/tar/setup clear eagle sp shell. Your CMOS should be initialized.
Give the SDU command
/tar/loadand follow the prompts.
load >prompt appears, give the command
installand follow the prompts.
One will get the following message if using the Bitsavers
File doesn't start with LMFL Skip to next file? (y/n)
Give the command
qto return to the SDU
Close the emulator by closing its window
Edit your config file file and change the SDU switch setting to 1
Restart the emulator. You should get a SDU prompt on the console.
configcommand to initialize the Lambda configuration. When asked if you want to change anything, type y and press enter.
cmd:prompt, give the command
If using a 2x2 Lambda, you will be asked which slot -- use 0.
lambda cmd:prompt, give the command
->prompt, give the command
Push enter to return to the lambda command level.
Give the command
xuntil config reboots the SDU.
At this point your machine is configured and you can save backups of your lam.yml, disk image, and CMOS image file.
At the SDU prompt, give the command
newbootto bring up the bootstrap program.
Command:prompt, give the command
bootto start lisp.
When the REPL arrives, evaluate
(si:set-pack-name "LISPM-A")to set the hostname.
(si:set-pack-name "LAMA LAMB")
(si:%halt)to halt Lisp.
When Lisp halts, press F11 to summon Newboot again
Command:prompt, give the boot command to cold-boot Lisp.
When the REPL arrives, evaluate
(fs:initialize-file-system)to format the LMFS. Answer
Yeswhen prompted for confirmation.
Push F12 to switch tapes to your distribution tape, if you have one.
Type F1-B to summon the Backup activity.
Select RETRIEVE from the Modes panel and RESTORE-FILES from the Commands panel; this will start to restore files immediately. When asked to login, use LISPM as your user.
Takes about three hours on a modern-ish PC.
When done restoring the distribution tape, reboot, load all patches, and save a new load band. To find a suitable partition, evaluate
(login 'lispm) (load-patches) (disk-save 2) ; Or some other suitable partition. (set-current-band 2)
If you get a warning about mismatches microcode, just answer that it is OK.
This is also a good time to make a backup (CMOS.RAM, disk image, and lam.yml).
If you want to poke around on the local file system, you can start
Dired by evaluating
(dired "lama: ~;*").
At this point you can follow the instructions included with the distribution tape. If it is a backup tape, simply restore it. If it is an actual distribution tape, it may have special loading procedures.
(Re)Compiling the whole system
To compile the whole system, which will only compile files that need to be compiled, evaluate:
If you've done many changes, it might be worth recompiling everything, to do that evaluate:
(make-system 'system ':recompile)
Assembling the microcode load
To assemble a new microcode load evaluate the following:
(load "sys:ulambda;ucode") (make-system 'ucode)
When using the Bitsavers distribution tape,
UC-LAMBDA-ARRAY.LISP will barf; open the file end save it without
To then load the resulting microcode (
SYS: UBIN; ULAMBDA LMC);
evaluate the form (this will load the latest LMC file):
(si:load-lmc-file t 2) ; Or some other suitable partition.
To test that the microcode loads, switch to the second CPU and summon
newboot (F11). At the
Command: prompt use the
to choose a microcode load to boot temporarily. When done, issue
boot to boot.
To make it current, evaluate
Generating a new cold load band
To load the Cold Load Generator, and to make the load band evaluate the following two forms:
(make-system 'cold) (cold:make-cold 2) ; Or some other suitable partition.
This takes about 20 minutes on a modern-ish PC.
Then one needs to start start the MINI server, issue F1-7 and in the
right panel evaluate
Switch to the second Lambda using F9, and evaluate
This will boot the cold load band, when that is done one can start
loading the rest of the system by evaluating
When this has finished, and the new system seems to be working, one can make the load band default by evaluating `(set-current-band "LOD2").
Making distribution tapes
We need two tapes:
Installation software, microcode and load band.
Regular backup of SYS tree
To make a distribution tape, load:
Then run, pick the type of tape you are making (source or options):
Install tape consists of the following:
$ tar tvf file-1.dat -rw-r--r-- 0/0 12480 1985-12-09 16:30 setup -rw-r--r-- 0/0 6236 1985-12-09 16:31 bigtape -rw-r--r-- 0/0 6552 1986-03-01 07:46 st2181 -rw-r--r-- 0/0 247 1986-06-18 03:34 version -rw-r--r-- 0/0 10240 1986-03-01 07:46 disk -rw-r--r-- 0/0 22704 1986-04-13 00:01 load -rw-r--r-- 0/0 30776 1985-12-09 16:36 2181 -rw-r--r-- 0/0 104728 1986-04-13 00:01 loadbin -rw-r--r-- 0/0 20540 1985-08-05 01:45 3com -rw-r--r-- 0/0 30514 1985-07-08 23:16 cpu -rw-r--r-- 0/0 26185 1985-08-05 01:45 lam -rw-r--r-- 0/0 30676 1985-08-05 01:45 mti -rw-r--r-- 0/0 35220 1985-12-11 04:52 quad -rw-r--r-- 0/0 17506 1985-08-05 01:45 quart -rw-r--r-- 0/0 25304 1985-08-05 01:45 ram -rw-r--r-- 0/0 18838 1985-08-05 01:45 tape -rw-r--r-- 0/0 27764 1985-08-05 01:45 vcmem
LMC1 (Lambda microcode)
LMC2 (Lambda microcode)
LOD1 (Lambda laod band)
When using a 2x2 setup one can debug the other processor, evaluate
(lam:setup) and choose the "local" option. This will setup the
debugger, to start it issue F1-RIGHT-CONTROL-D. In the top panel,
LAM for novice and you can use the right side menu for poking
The Lambda supports multiple disk units, to use them the labeling of partitions is important. The first character must correspond to the unit the drive is attached too. So to keep a FILE partition on unit 1 (instead of unit 0), it has to be named 1ILE or 1FILE.
The last digit of a partition name that contain "writable" data is used by the second CPU. E.g, PAGE, METR, FILE are used by the first CPU and PAG1, MET1, FIL1 by the second.
N.B. The real Lambda could only really handle 2 disk units, the controller does support 4 units which is also what LambdaDeleta supports.
Setting up the
ip tuntap add ldtap mode tap ip link set ldtap up ip addr add 10.0.0.1/24 dev ldtap
In SYS: SITE; SITE.LISP see that the following, or equivlent exists:
(:NETWORK-NAMES '((("CUSTOMER-NETWORK") ( (:INTERNET "18.104.22.168" "255.255.255.0") (:CHAOS 7))))) (:DEFAULT-INTERNET-ROUTING "10.0.0.1")
And in SYS: SITE: HOSTS.TEXT:
HOST LAMBDA-HOST, [INTERNET 10.0.0.1],USER,UNIX,VAX HOST LAMBDA-A, [INTERNET 10.0.0.2, CHAOS 3430],USER,LISPM,LISPM,[LAM-A,LAMA]
Replace IP addresses accordingly.
Recompile all site files, and re-configure the network:
(make-system 'site :recompile) (network:configure)
This is as good place as any to make the changes permanent by saving
the world using