Fri Sep 12 11:25:35 CEST 2008

Incremental development

As already hinted before, the Staapl framework contains some tension
between ``transparent'' and ``toplevel'' development frameworks.


  Also called ``image based'' development.  Typically in a dynamically
  typed language it is possible to create and change definitions
  during interaction.  This has traditionally been the model in Lisp,
  Forth and especially Smalltalk.  This model is heavy based on
  mutation and the sequence of code (re)definitions.


  Here application structure is a property ONLY of the source code,
  and does not depend on load order.  It is essentially declarative.
  All definitions are permanent, and cannot be redefined.  This
  approach is typically taken in statically typed languages, but is
  also used in the PLT Scheme module system.

Staapl allows you to use both approaches, mostly coming from PLT
Scheme's "load" and "require" forms.  It is possible to create
applications with a fully static module structure which can then be
interactively extended.  The workflow looks like this:

 1. build an application kernel using the module system (this can be a
    single module with a flat namespace)

 2. compile it and upload the kernel image to the target system.

 3. connect a console to the target system, and incrementally upload
    new code.  when it's stable, add it to the kernel and reflash the
    whole application.

In order for 3. to work, the console application needs to know where
to find the kernel code, since the target does not contain a symbol
table.  This can be done by either not leaving the compiler after
compiling and uploading the kernel, keeping all the symbol tables
alive, or by reconstructing this state using a dictionary file.  Such
a file looks like this:

  (require (planet zwizwa/staapl/prj/pic18))
  (forth-load/compile "/tmp/foo.f")
  (words! '((asdf code 0)))
  (console! '("/dev/staapl0" #f))
  (pointers! '((code 1) (data 0)))

The first two lines initialize the compiler namespace with the base
language.  The third line re-loads the top application file,
reconstructing all macros and code.  The fourth line makes sure the
target words are linked to the correct addresses.  The remaining lines
set console parameters and pointers to free code and data memory

The catch is in the 'words! and 'pointers! procedures.  The source
code can get out of sync with the binary code uploaded to the
microcontroller.  When the application has changed compared to the
code present on the microcontroller, these two commands are relevant,
as they will replace the dictionary compiled from the application
source so it reflects the older, out of sync target code, to ensure
interactive compilation will still work.

This approach is intentionally not transparent.  There are cases where
it is more convenient to let the application source code and on-target
compiled code get slightly out of sync, to benefit from the shorter
edit-compile-upload cycle which doesn't need a target reboot.  In
those cases however it is important to have the new _macros_ available
for interactive compilation.