Legal Notice

Copyright (c) 1998 Massachusetts Institute of Technology This material was developed by the Amorphous Computing project at the Massachusetts Institute of Technology Artificial Intelligence Laboratory. Permission to copy and modify this software, to redistribute either the original software or a modified version, and to use this software for any purpose is granted, subject to the following restrictions and understandings. 1. Any copy made of this software must include this copyright notice in full. 2. Users of this software agree to make their best efforts (a) to return to the MIT Amorphous Computing project any improvements or extensions that they make, so that these may be included in future releases; and (b) to inform MIT of noteworthy uses of this software. 3. All materials developed as a consequence of the use of this software shall duly acknowledge such use, in accordance with the usual standards of acknowledging credit in academic research. 4. MIT has made no warrantee or representation that the operation of this software will be error-free, and MIT is under no obligation to provide any services, by way of maintenance, update, or otherwise. 5. In conjunction with products arising from the use of this material, there shall be no use of the name of the Massachusetts Institute of Technology nor of any adaptation thereof in any advertising, promotional, or sales literature without prior written consent from MIT in each case.

Programming Overview

Programming for the Gunk machines on the wall is little more than calling the appropriate OS/Library routines and handling the return values. An in-depth understanding of HC11 code is not necessary. In fact, much can be done with only a few machine language commands: LDAA #$56 - LoaD the Accumulator A register with the immediate value $56 (in hex) LDAB FOOA - LoaD the Accumulator B register with the value from the user register A LDX #1234 - LoaD the X index register with 1234 decimal LDY #$00 - LoaD the Y index register with 0000 hex. INCA,INCB,INX,INY - INCrement the appropriate registers INC FOOB - INCrement the user register B DECA,DECB,DEX,DEY,DEC FOOC - DECrement those registers JSR DELAYINT - Jump to SubRoutine (DELAYINT) CMPA FOOD,CMPB #$5F - CoMPare the values in the registers and set flags appropriately. BEQ ADDRESS - Branch if EQual (Z=1) BNE ADDRESS - Branch if Not Equal (Z=1) For more, consult the back of the HC11 user manual. (Ask for the pink book.) Note: Accessing RAM directly (instead of using the predefined structure) may yield unpredictable results. If you find it necessary to have more control over RAM or you wish to add more variables of different types, please consult me (wbeebee@martigny.ai.mit.edu) first.

HC11 Programming Examples and Tutorial

Example 1: The following eleven-byte user program causes a GUNK box to light its LED sequentually: LED 1, then LED 2, then LED 3, then LED 4, then LED 1, etc. ORG USERPROG every User Program begins with a space and ORG USERPROG VER FCB $01 It must begin with a version number byte. STARTLOOP LDAA #$08 Initialize A (usu. state variable of program) LIGHTLOOP JSR DELAYPOLL Delay while polling for programs, display value in A LSRA Logical Shift Right A BNE LIGHTLOOP If it's Not Zero, Branch to LIGHTLOOP BRA STARTLOOP Otherwise, Always Branch to STARTLOOP PROGEND NOP every User Program ends with this line Note: Machines running programs with the same version number will not infect each other. Programs must explicitly poll for other programs during any wait state, otherwise they cannot be infected. (This will hopefully change after the wired-or connects PORTD with the IRQ line to enable event-driven message handling. I already discussed this hardware modification with Pat Thompson and it's slated to appear in the kludge zone.) In the meantime, amorphous algorithms shouldn't absolutely depend on event-driven message handling. If you don't need it, don't use it. Example 2: This program counts down from 15: ORG USERPROG VER FCB $03 STARTLOOP LDAA #$0F Counting down from 15 LIGHTLOOP JSR DELAYPOLL DECA Decrement A instead of Logical Shift Right A BNE LIGHTLOOP BRA STARTLOOP PROGEND NOP Example 3: Now for some communication! The following program is the famous circle demo or hop counter (33 bytes): ORG USERPROG VER FCB $04 A and B were automatically initialized to 0 PROGBEGIN COMA Take the COMplement of A - in order to flash. JSR DELAYINT DELAY, but be open to INTerruptions CMPB #$04 Was a sensor hit? BHS SENSEHIT If so, goto SENSEHIT TSTB Did the delay run out without interruptions? BEQ PROGBEGIN Then toggle lights and delay again LDAA #$7F A message was received! BRA SENDNEIGHBORS So, display it and send it to your neighbors SENSEHIT LDAA #$01 I was hit - display and broadcast 1. SENDNEIGHBORS LDAB RBUF What do the neighbors have to say? INCB Increment it JSR LESSAB Put the LESSor in A and the greator in B STAA PORTB Display the lessor LDAB #$01 And broadcast it JSR BROADCAST BRA SENDNEIGHBORS Keep on broadcasting it Note: This program has a bug. Can you find it? Hint: In amorphous computing, you have to expect erroneous or garbled messages to occur frequently. A single bad message may cause a poorly-designed program to do unexpected things. Further Examples: Here's the original FIREFLY program. It's actually a lot simpler than it looks. Mentally break it down into blocks and look at the function of each block. If you're feeling really ambitious, here's the more modern FIREfly/CIRCle program. Note: the Firefly/Circle program as listed is actually far more complicated than it needs to be in order just to synchronize. It is actually two programs in one - the Firefly program and the Circle program. It also has additional code so that it is fully configurable from a user interface and uses OSRPC to reconfigure other machines.

M68HC11 on the WWW

Motorolla site, etc. Motorolla's Application Snapshots tech notes Archive of HC11 mailing list Using hcload

Memory Layout

EEPROM Configuration: $F800 = EEPROM $F820 = USERPROG (total 320 bytes) controlled by USERPROG $F960 = USERPROGEND $F980 = LOADER RAM Memory Configuration: MESSAGING VARIABLES (4 bytes) STACK $5F to $04 (92 bytes) HEAP $60 to $B7 (88 bytes) -- also used from RAMPROG MSG OUT $B8 (36 bytes) -- also used from RAMPROG MSG IN $DC (36 bytes)

User Program Notes

USER PROGRAM must start with the version number. Must poll for new messages (OSPOLL) at least every RDELAY delay cycles. User program can use loader supplied subroutines. User Program must be no larger then 3840 bytes or run over USERPROGEND Program has access to FOOA - FOOD, contiguous 16-bit variables.

Basic OS/Communication Routines

Procedure: OSSEND Purpose: To send a message to a particular destination. Arguments: SBUF = message SLEN = length of message + tag (TAG[3]:LENGTH[5]) TAG values: DATA 000 VERSION 001 PROGRAM 011 OS 111 DST = destination of message SFLAG = 0 Returns: SFLAG = 0 = success 1 = failure, no response 2 = line in use already Notes: MUST save all registers, all get trashed
Procedure: OSRECV Purpose: To receive a message. Arguments: RFLAG = sources mask (where bit = 1 if want to receive from that source) Returns: RFLAG = 0 = success, 1 = no message or failure 2 = collision RBUF = message SRC = message source RLEN = length of message
Procedure: OSPOLL Purpose: Polls for a message from any neighbor. Arguments: RFLAG = 0 Returns: RFLAG = 0 = received message SRC = source RLEN = TAG[3]:LENGTH[5] RBUF = message 1 = no message 2 = collision does not return if NEW PROGRAM Notes: Trashes B,X,Y and may trash RBUF/RLEN/SRC contents if new message It polls the line for messages using OSRECV If RFLAG=0, then checks the TAG If TAG=DATA, simply return to caller If TAG=VERSION, compare version If TAG=OS, perform the OS call indicated in RBUF If different, call OSRECVPROG Now handles unrestricted RPC requests.
Procedure: OSSENDPROG Purpose: Attempts to send a program to all neighbors. Arguments: None Returns: Nothing (trashes A) Notes: For each neighbor, OSSENDPROG sends a version number, gets back a yes/no (aborts after timeout) If yes, it sends the user program.

Library of Procedures


Message Handling Routines

Broadcast Routines

Procedure: BROADCAST Purpose: To broadcast a message to neighbors. Arguments: B=0 Broadcast a message in SBUF of length SLEN B=1 Broadcast a number in A (preserves A) Y= How many times to broadcast (#$1000 takes approx. 10 sec.) Returns: B=0 Nothing interesting happened B=1 A message was received B=2 A new message was received B=3 The new message has a different stamp B=4 The light sensor was hit B=5 The button was pressed Y= When the interruption occurred Notes: This section would, ideally, become a background task kicked off or managed from a high level by the program and run by the OS using interrupts or a separate thread.
Procedure: POLLNEWMESSAGE Purpose: To poll for a message and MSGCOMPARE it with the last one. Arguments: Nothing Returns: B=0 no message received B=1 message received B=2 new message received B=3 new message has different stamp
Procedure: MSGCOMPARE Purpose: To compare two messages using OSCOMPARE. Arguments: X=Pointer to first message Y=Pointer to second message A=Length of message Returns: B=0 messages are the same B=1 messages are different B=2 messages have different stamps
Procedure: MSGCOPY Purpose: To copy the message pointed to by X into Y using OSCOPY. Arguments: X=Pointer to first message Y=Pointer to second message Returns: Nothing
Procedure: SENDCHECKRET Purpose: To broadcast or send a message while waiting for a return receipt Arguments: A=return receipt to check for Y=timeout SBUF=message to send DST=destination, if DST=0 then the message is broadcasted Returns: B=0 successful B=1 timed out while waiting for return receipt B=2 message was misinterpreted (uh-oh!)

Generic Message Format

USERPROG messages should use this generic header: SBUF: Send message buffer OUTMSGNUM for transferring 8-bit or 16-bit numbers OUTMSGTYPE message type - for USERPROG interpretation OUTMSGID to identify this message OUTMSGSENDID to identify the sender OUTMSG message text RBUF: Receive message buffer INMSGNUM for transferring numbers INMSGTYPE message type - for USERPROG interpretation INMSGID to identify this message INMSGSENDID to identify the sender INMSG message text

Message Formatting Routines

Procedure: RESEND Purpose: To rebroadcast the message just received. Arguments: RBUF=message to broadcast Y= How many times to broadcast Returns: B=0 Nothing interesting happened B=1 A message was received B=2 A new message was received B=3 The new message has a different stamp B=4 The light sensor was hit B=5 The button was pressed Y= When the interruption occurred Notes: The "immortal" message problem can be solved either asynchronously (RESEND + STAMP) or synchronously (FIREFLY).
Procedure: STAMP Purpose: To identify this machine as the originator of an outgoing message. Arguments: SBUF = (un)stamped message Returns: SBUF = (re)stamped message

Remote Procedure Call

Procedure: OSRPC Purpose: Send an OS Remote Procedure Call (proxy) to invoke any (unrestricted) subroutine on another machine. Arguments: X=address for remote machine to JSR to (preserved) A,B,Y are copied to remote machine DST=destination if DST = 0, then the message is broadcasted Returns: B=0 RPC received successfully B=1 RPC timed out (approx. 1 second) B=2 RPC misinterpreted (uh-oh!) Notes: Only one RPC call may be processed at a time. This may change in the future.
Examples of RPC: Procedure: OSREQPROG Purpose: To request a program to be transferred. Arguments: none Returns: never
Procedure: OSSETRAM Purpose: To store the value of A in the memory address pointed to by Y Arguments: A=value to store in RAM Y=RAM address Returns: to the program running on the remote machine Notes: This procedure is called on the remote machine through RPC.
Procedure: OSREQUEST Purpose: To send an OS request and wait for a return receipt Arguments: DST=destination, if DST=0, message is broadcasted SBUF=message Returns: B=0 Request received successfully B=1 Request timed out (approx. 1 second for broadcast) B=2 Request misinterpreted (uh-oh!)

User Interface Routines

User configuration section - routines to allow user to configure demo Procedure: SETNUM Purpose: To allow the user to set parameters in a program. Arguments: A=Number to set Returns: A=New number Notes: SETNUM displays A and waits for the button to be pressed to set it. Meanwhile, pointing the laser at the sensor increments A.

Delay Routines

Procedure: DELAYINT Purpose: Delay, but be open to INTerruptions (ie. DATA) coming in. Arguments: B=0 Assume a standard delay of $0400, and display A in lights B=1 Specify a delay factor Y= Delay factor if B=1 Returns: B=0 Nothing interesting happened B=1 A message was received (SRC contains source) B=2 A new message was received B=3 The new message has a different stamp on it B=4 The light sensor was activated B=5 The button was pressed Y= When interruption occurred Notes: The phase of reception keeps changing so that it is unlikely that a program broadcasting messages at a constant rate would fail to communicate to a box in a DELAYINT loop.
Procedure: DELAYPOLL Purpose: To delay for a period of time and poll for programs. Arguments: None Returns: Nothing
Procedure: LIGHTDELAY Purpose: Display a number for a period of time. Arguments: A=Number to display Returns: Nothing
Procedure: YDELAY Purpose: Delay for a long period of time. Arguments: Y=Time to delay Returns: Nothing
Procedure: DELAY Purpose: To delay for a short period of time. Arguments: X=Time to delay Returns: Nothing


Procedure: OSCOMPARE Purpose: To compare to buffers. Arguments: X=Buffer1 Y=Buffer2 A=length in bytes Returns: B=0 buffer contents are the same B=1 buffer contents are different
Procedure: OSCOPY Purpose: To copy data from one address to another. Arguments: X = from address Y = to address A = number of bytes Returns: nothing
Procedure: SENSOR Purpose: To detect if a sensor was activated. Arguments: None Returns: B=0 Nothing interesting happened B=1 The light sensor was hit B=2 The button was pressed
Procedure: LESSAB Purpose: To return the lesser of two numbers. Arguments: A,B Returns: A=lesser of A,B B=greater of A,B Notes: This should be a machine-language instruction.