Note:

To download a file, click on the link with the right mouse button. In the menu then select Save Link as ... This avoids attempts of your browser to interpret the content.


What is there for download

barebone.tgz

reorder.seq, reorder.f

switch.seq

spi-driver

State Machine Preprocessor for C

Driver for the Agilent 10887P calibrator board


barebone.tgz

BareBone is a simple command line program for playing audio CDs under Linux. It is based on the modules "driverifc.c" and "cdstruct.c", that are modified versions of "hardware.c" and "struct.h", respectively, from the elaborate X11 CD program known as WorkMan. BareBone was written with two goals: Give the user a real simple program to play audio CDs and allow him to use this program in scripts (e.g. .profile).
SYNOPSIS
   barebone  [ -v | -h | -s | -e | t start ]
           -v : version
           -h : help
           -s : stop CD
           -e : eject CD
     -t start : play CD, beginning at track 
Type    barebone   to play the whole CD.


reorder.seq (for FPC)

reorder.f (for Win32Forth, ported by Heinrich Möller)

Important!

If you downloaded the file REORDER.SEQ before 30-May-2001 you must dowload it again! There was a bug in the previous version. Sorry for the inconvenience.

Do you like FORTH because you can solve tasks rather fast and easy? Are you annoyed by all the SWAP, DUP, FLUP, OVER, UNDER, PICK, PUCK, SICK, SUCK? If you answered yes to both of the questions you can get a good deal of relief by using REORDER. It does exactly what you tell it to do with your parameters on the stack. Download REORDER.SEQ and load it into F-PC ( a Forth for the PC by Tom Zimmer ) and you can use it (together with the old words, if you want). Or download REORDER.F for Win32Forth.

The usage of REORDER is straightforward:

REORDER ( fred bob joe bill gates -- bob joe fred )
This example drops the top 2 items ( bill gates ), and effectively picks the ( then ) 3.rd and puts it on TOS, just like the stack comment shows. Of course you can use an item more than once on the right side (but all items on the left must have unique names). So
REORDER ( a b c d -- a b c d d c b a a a a b b b c c d )
is totally ok. But don't be afraid that REORDER will compile a lot of stack operations for this. The example above are only 71 bytes! And pure assembly code - fast! And try to do this fiddling with the parameters with your "normal" stack operations. You will end up (after 1001 crashes and hours later) with much more space consumed and with a much slower solution. The "secret" of REORDER is a simple optimizing algorithm:
  1. Scan the part between the opening bracket up to the double dashes and build a table with the names of the items and their order found ( the first after the bracket is assigned 0, the second 1 and so on - in the last example "a" gets 0 assigned, "b" 1, "c" 2 and "d" 3). Then subtract the biggest index from all of them (in the example this means subtracting 3 from them to get -3, -2, -1 and 0 for a b c d ). These indices now represent the locations relative to the TOS of the items. From now on these items are refered to only by the corresponding index.

  2. Now scan the right side from the hyphens to the closing bracket and build a byte string of indices according to the order of parameters found in the input stream. (For the above example this would result in the string
            -3 -2 -1 0 0 -1 -2 -3 -3 -3 -3 -2 -2 -2 -1 -1 0
    because we wrote:
        "--  a  b  c d d  c  b  a  a  a  a  b  b  b  c  c d
    on the right side.)

  3. Next check the change in size of the stack - does it grow, shrink or stay the same? If it will be bigger after the reorder then add the needed amount to the stack right now (i.e. subtract twice as many bytes from the SP) and subtract the number of additional items from all the indices (they lay now "deeper" in the - adjusted - stack). If the stack shrinks (some sort of DROPs in effect) just remember the number of items less on it afterwards, but do not change the SP right now. This was done because the same REORDER shall be usable on a multitasking OS and the stack never may be "unprotected" - i.e. there must never be any items that are referred that are not "on" the stack but beyond the SP. Do not modify the indices, too. If the stack's size does not change do nothing here.

  4. Scan the byte string (possibly modified by the previous step ) to check if there are items that get overwritten but are needed. Take the first that wanders to a save location, compile a load-store sequence to do this and correct the index of this parameter so that it reflects the new position on the stack. Do this for all endangered items. (In the above example there are none, but in ( a b c d -- d a b c d ) all are candidates for the above procedure. Here first the SP is advanced, then d is copied to the (new) TOS (and still held in one processor register!). Next we find that d is to be placed where a is right now. So compile a load of "a" to a second processor register and a store of the first register (containing still "d") to the location where we got "a" from. This frees this register, as "d" is no longer needed (both copies have been done).

    Now with "a" in the second register we find that it's destination is currently occupied by "b". So we compile a load to the first register for "b" and a store of the second to the location where we got the "b" from (this places "a" where it has to go to and frees the second register, as no more copies of "a" are needed. Next we load "c" and store "b" and finally we store "c". We do not have to load "d" as we made the copy in the first of our load-store sequences.

    This procedure works whether the stack grows, shrinks or stays the same. The only thing to care here is that we first make all copies (or moves) to items that are on the stack afterwards in the additional locations.

    (If that procedure reminds you of something but you do not know right now of what - think of a sort procedure: bubble sort. Our procedure is a derivate of it with the only difference that bubble sort always takes adjacent items and we choose the item to exchange according to the byte-string.)

  5. If the stack shrunk by the REORDER then adjust the SP now.

  6. Finish the procedure with a normal NEXT.
One word about the speed of REORDER in comparison to the "normal" stack operations: For all but the most primitive words REORDER is significantly faster. Only the simple words DUP, DROP, SWAP, OVER are slightly faster than REORDER. But the increased readability of your source code outweighs this by far and wide. Good efficiency!


switch.seq

Introduction

Very often you need a variable just to remember the state of your program. This may be the state of the Forth compiler itself (usually named STATE) or something else. Usually you write a construction like this:
variable MOTOR

.... MOTOR @                            \ this reports the current state
.... MOTOR OFF                          \ set the variable to off
.... MOTOR ON                           \ and this sets it on
This seems to be a good way to do the job, but when the two different states have dissimilar functions, like that famous STATE in Forth, it becomes difficult to remember what is done in which state. A way to elivate this could be a colon definition like:
: compiling
        state on ;                      \ give it a meaningful name
This is OK for small projects, but becomes cumbersome for bigger ones as people tend to "forget" these redefinitions - they use ON and OFF in their code.

Solution

The SWITCH: construct is easy to use and effective with memory and time. It's syntax is:
SWITCH: < switch name > < word to set it off > < word to set it on >

Example: SWITCH direction?  counter-clockwise clockwise
This declares three words: DIRECTION?, COUNTER-CLOCKWISE and CLOCKWISE. When you want to get the current state of the switch you use
        DIRECTION? ( -- state )
that leaves the current state on the stack ( 0 or -1 ). To set it on (clockwise) in our example you use
        CLOCKWISE ( -- )
and
        COUNTER-CLOCKWISE ( -- ) 
to set it off.

The main advantage is the decoupling of the function from the implementation. On a processor with good bit operators you can implement it easily to use only one bit in a storage cell. This saves space in embedded applications.

Implementation on small systems

Small systems (on microcontrollers) sometimes must "live" with as little as some hundreds of bytes of RAM (on chip), but must remember the states of many output values (not pins, unless their state cannot be read in at any time). Wasting a full byte or even a full word for one bit is not tolerable there. One way is to carefully handselect the bits in some bytes (or words) and use them consistently throughout the code. But this is errorprone. Why not let the compiler do the job? (And in Forth you can extend the compiler on the fly!)

The following guideline assumes that the processor is an 8-bit type (like the Z80). But the extension to any width is simply a redefinition of one constant (BUS_WIDTH). Following is the symbolic code to implement the SWITCH: in any Forth.

8 constant bus_width                    \ how many bits our system is wide

variable (next_bit)                     \ what is the next free bit in the
                                        \ currently used memory cell (of width
                                        \ BUS_WIDTH)

variable (current_cell)                 \ holds the address of the current cell

: get_next_bit ( -- adr bit# )          \ find the next free bit in the current
                                        \ cell, allocate the next if current is
                                        \ full
        next_bit @                      \ what is the next free location?
        bus_width >                     \ is it beyond the cell?
        IF                              \ yes, we must allocate a new cell
          1 next_bit !                  \ we start with the 1.st bit
          here                          \ where we want to put the new cell
          (current_cell) !              \ remember the adr
        THEN                            \ here we come with enough space in the cell
        (current_cell) @                \ leave the adr on the stack
        (next_bit) @                    \ and the bit# to use
        (next_bit) incr                 \ increment the bit# to use
        ;

: SWITCH:                               \ becomes a compiler extension
        add-name-to-dictionary          \ name of the switch to the dictionary
                                        \ cfa is set to HERE
        get_next_bit ( -- adr bit# )    \ get the next free bit and the adr
        over over                       \ we need both values again
        compile-"Test bit bit# at adr adr" \ LD A,adr BIT A,bit# (on a Z80)
        extend-to-word                  \ JZ unnest   LD A, -1  unnest:
        compile-unnest                  \ end the execution here
                                        \ is JUMP NEXT or RTS, depending on system

        add-name-to-dictionary          \ name of the off state word, cfa=here
        over over                       \ we need them a last time for the on state
        compile-"Clear bit bit# at adr adr" \ LD A,adr RES bit# LD adr,A
        compile-unnest                  \ end the execution here

        add-name-to-dictionary          \ name of the on state word, cfa=here
        compile-"set bit bit# at adr adr" \ LD A,adr SET bit# LD adr,A
        compile-unnest                  \ end the execution here
        ;
That is all to use just one bit for it (if the processor has a good bit manipulation instruction set)!

The file SWITCH.SEQ does not use this technique because the x86 processors are very slow with bit operations and FPC is running on a PC. But it gives you the convenience of the SWITCH construct instantly.


spi-driver-1.0.tgz (Linux 2.0.x kernels)

spi-driver-2.02.tgz (Linux 2.2.x kernels) (Bugfix 29.Oct.2001)

spi-driver-2.1.tgz (Linux 2.2.x kernels) (Catches an IRQ, can be checked via ioctl, otherwise V2.02)

Please note: With the older kernels it was legal to write to a user buffer, supplied in a WRITE from the user program. This no longer supported and the driver is modified accordingly in version 2. This affects all programs that use the driver. While previously it was ok to write something to the driver and expect the driver to return the new data in the same buffer on return, it is now illegal. If you need data from the driver you must do a read operation immediately after the write. But this is the only change.

If you have downloaded V2.0 please get the new version 2.02 above. There was a small bug in version 2.0. Or you fix it yourself: Put this line as the last line in function cleanup_module (file spi.c):

if (spi_buf != NULL) kfree (spi_buf);

The driver should work under 2.4.x kernels, but this is still untested. The version 2.1 introduces an optional feature: It can catch the INT (IRQ) from the port and remember it. The process having the spi-device open can check that via an ioctl call. See the documentation for details. If you do not need that feature V2.0 will do it. (Note: only one process can have /dev/spi open at any given time. This is a limitation of the SPI-Bus per se, because the driver does not know when a transaction on the bus is complete, as you can do segmented transactions.)

The SPI-bus (from Motorola) and it's companion, the MicroWire-bus (from National Semiconductor), are 3-wire serial busses with TTL-level that are designed for communication with a lot of devices, like ADCs, DACs, ports, EEROMs. Devices for these busses are available from, among others, Motorola, National Semiconductor, Maxim, Harris, Siemens.

Both busses differ only in simple terms, so one driver can talk to chips of both families, even when they are mixed on the same bus. The driver is called spi-driver simply because it is short (and the author knows that one driver can handle both ;-) ).

To have the spi-driver in your kernel you need the following files:

	spi.c
	spi.h
	spi-driver-ifc.txt
	spi-driver-install.txt
The first two are the ones which are REALLY necessary; the others are simply instructions on usage and installation of the driver. You can put them wherever you want, but the first 2 must be copied to certain locations, as instructed in spi-driver-install.txt

As the driver is a module you have two choices where to put the files, but read spi-driver-install.txt for that. The usage afterwards is identical in both cases. NOTE: The spi driver uses a parallel port and the lp driver snatches all ports when it is loaded. So you MUST make the lp driver a module, too. (More in the installation instructions.)

First unpack the .tgz file at some convenient location. It does not create any directories. You have to do it manually if you want the files to go to a specific one. Then run make.

Thanks a lot to Alessandro Rubini who proposed to make the driver a module and helped me to get it done.


State Machine Preprocessor for C

This little utility is provided to make it easy for a C programmer to use state machines. It introduces 4 new keywords. If you want to read a more thorough description of the benefits of this utility, then read this document. Or go ahead and download the utility straight ahead. There is an executable package for DOS and the Turbo Pascal 6.0 source. Neiter ZIP contains the aforementioned introduction to the preprocessor. A Linux version of it is under development, but will be delayed due to lack of time.

Driver for the Agilent 10887P

The 10887P calibrator board is shipped with software for DOS/Windows only. So, if you want to operate it under Linux you need a driver for it. We wrote a simple one with most of the features still untested. Download it at your own risk - it is still early beta! No, don't do it!!! Contact the site manager instead. It still has some serious bugs! It is supplied in source code, but is easily compiled into a module. We have tested it only on Debian Linux 2.2.x and not all features, because we did not use the quad input, nor some other features of the board.

Unfortunately we do no longer have this board here, so we cannot improve the driver. You are free to make changes to the software at will, but notify us, please. Contact the webmaster and mail your modified code so that we can keep this site as current as possible and give you the credits you deserve.

As soon as some modifications are made by someone to the software we will start to give it version numbers and in the future you will then find files with version numbers. Consider this to be version 0.1.

Note: With the package comes a file with the ending .dll . This contains the firmware for the board. Agilent allowed us to supply it with the driver, but explictly forbids any modifications to, or reverse engineering of, that file. Honour the support of Agilent, please.


© Paul Elektronik 1998-2002