M68HC11 GUNK API Book
![](rule.gif)
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
blurb
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
Miscellaneous
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.
wbeebee@martigny.ai.mit.edu