Thursday, 29 December 2011

USB Stick Microcontroller Dev Boards

A USB programmable microcontroller is a cheap and easy way to begin experimenting with microcontroller projects. I've recently been playing with 6 USB sticks which can be picked up for under £25 ($40) and discovered three I would recommend, the Micropendous, Minimus and eZ430. Have I missed your favourite USB stick based microcontroller?

Micropendous3

The Micropendous3 (top left) contains an ATMEL AVR AT90USB647 microcontroller with 64K flash, 2K EEPROM and 4K SRAM and allows access to the MCU's 48 I/O lines. The board also supports the AT90USB1287 with 128K flash, 4K EEPROM and 8K SRAM. Support and development software are available online.

Maximus AVR USB 1.2

Despite it's name the Maximus AVR 1.2 (top right) is based on Microchip Technology's PIC18F4550 microcontroller with 32K flash, 2K SRAM and 256 bytes EEPROM. Unfortunately the board layout doesn't allow access to the MCU pins.

Minimus AVR USB 32K

The Minimus 32K (middle left) uses ATMEL's ATMEGA32U2 with 32K flash, 1K EEPROM and 1K SRAM. The board allows access to the MCU's 22 I/O lines. Development software is available online.

eZ430-F2013

Texas Instrument's eZ430-F2013 (middle right) has a detachable target board containing a MSP430F2013 microcontroller with 2K flash and 128 bytes SRAM. The board allows access to all MCU pins. The eZ430 is supplied with development tools for Windows and support is readily available online. The instruction set is easy to learn with just 27 instructions and 4 addressing modes.

Maximus AVR USB 1.0

The Maximus AVR 1.0 (bottom left) is based on the ATMEL AT90USB162 microcontroller with 16K flash, 512 bytes EEPROM and 512 bytes SRAM. As with the later version, the layout doesn't allow access to the MCU pins.

µRlink ST7Ultralite Primer v1.1

The ST7Ultralite (bottom right) is a board based on ST's 8-bit ST7FLITEUS microcontroller with 1K flash and 128 bytes EEPROM. The slightly odd looking board features a light sensor and buzzer and is supplied with a development environment for Windows. Unfortunately the IDE refused to install and there's little information online.

Sunday, 6 November 2011

A Bibliography of Programming Games

The Programming Games Bibliography is an attempt to compile a complete list of articles / papers on the subject. A Programming Game is played by writing programs to compete against each other, typically by attempting to disable opponents in the memory of a virtual computer or by controlling simulated battle robots.

Please help complete the list by leaving a comment if you remember an article not listed, even if you can only recall vague details. :-)

Bibliography

  • Vyssotsky, Victor A. Darwin: A Game of Survival and (Hopefully) Evolution.
    New Jersey: Bell Telephone Laboratories, 1961.
  • 0 "Computer Recreations: Darwin."
    Software: Practice and Experience 2 (Jan-Mar 1972): 93-96.
  • Edmunds, William "Robotwar: A Wargame for All Programmers."
    Computer Gaming World (Nov-Dec 1981): 13-16,33.
  • "Computer Gaming World's Robotwar Tournament."
    Computer Gaming World (Nov-Dec 1981): 17.
  • Feigel, Curtis "Robotwar."
    BYTE (Dec 1981): 24-34.
  • "Robotwar: Tournament Results."
    Computer Gaming World (Mar-Apr 1983): 30-31.
  • Hoffman, Paul S. "Robots Maneuver Humans Into Programming."
    The Rainbow (Apr 1983): 140-142.
  • Calle, Carlos "Robot Battle."
    HOT CoCo (Sep 1983): 53-54.
  • "We Have a Draw! Robotwar Tournament Results."
    Computer Gaming World (Apr 1984): 36.
  • Dewdney, A. K. "Computer Recreations: In a game called core war hostile programs engage in a battle of bits."
    Scientific American (May 1984): 14–22.
  • "4th Annual Robotwar Tournament."
    Computer Gaming World (Jan 1985): 9.
  • Dewdney, A. K. "Computer Recreations: A Core War bestiary of viruses, worms and other threats to computer memories."
    Scientific American (Mar 1985): 14-23.
  • "Nobody Wins 4th Annual CGW Robotwar Tournament."
    Computer Gaming World (Jun-Jul 1985): 9.
  • Martínez Lara, Sergio "Batcode, una auténtica batalla dentro de tu ordenador."
    MICROHOBBY 70 (18-24 Mar 1986): 22-23.
  • Martínez Lara, Sergio "Batcode, una auténtica batalla dentro de tu ordenador (II)."
    MICROHOBBY 71 (25 Mar - 1 Apr 1986): 28-30.
  • Martínez Lara, Sergio "Batcode (III)."
    MICROHOBBY 73 (8-14 Apr 1986): 28-29.
  • Martínez Lara, Sergio "Batcode, una batalla dentro de tu ordenador (y IV)."
    MICROHOBBY 74 (15-21 Apr 1986): 28-29.
  • Eliraz, Ziv "Core Wars."
    Dragon User (Sep 1986): 16-21.
  • Dewdney, A. K. "Computer Recreations: A program called MICE nibbles its way to victory at the first Core War tournament."
    Scientific American (Jan 1987): 14-20.
  • Edgar, Gerald A. "Darwin: A survival game for programmers."
    Computer Language (Apr 1987): 79-86.
  • de Weger, Mark "Battle of the RAM."
    The Micro User (Jan 1988): 42-43.
  • de Weger, Mark "The program strikes back."
    The Micro User (Feb 1988): 52-54.
  • Dewdney, A. K. "Computer Recreations: Of worms, viruses and Core War."
    Scientific American (Mar 1989): 110-113.

Friday, 8 July 2011

Darwin: Celebrating 50 Years of Programming Games

screenshot from Darwin-80
Darwin was the earliest programming game, invented by Victor Vyssotsky in August 1961. The idea of the game was to write a program to out-replicate and disable all opponents.

Each program had a number of protected locations and interacted via three functions:

  • PROBE - return the start, end and owner of a memory block
  • CLAIM - reserve memory
  • KILL - disable a program

If a protected location was PROBEd the current program lost control. A CLAIM or KILL could only be used on a location which had previously been PROBEd.

Douglas McIlroy coded Darwin on Bell Labs' IBM 7090 and the game slowly progressed until an unbeatable program emerged, designed by Robert Morris.

Robert's program used an adaptive search. If the program PROBEd an opponent and lost control it would avoid reusing the same offset. A successful offset would be stored then used for future PROBEs and to initialise new copies of itself. Robert's program adapted to become a specialist killer.

In 1972 0 (Aleph-Null) published the rules of Darwin in Software Practice and Experience, inspiring a number of new implementations. In 1987 Gerald Edgar published his 8080 version to accompany an article in Computer Language.

Unfortunately Darwin faced a major problem. Programs were written in machine language and could only compete against others written for the same computer. When A. K. Dewdney introduced Core War in 1984 he addressed the limitation by defining the MARS virtual computer and Redcode, a simplified assembly language.

Although Darwin has been consigned to the history book, I'll never grow tired of reading about it! Do you remember playing Darwin? If so, I'd love to hear the details.

References


  • 0 "Computer Recreations: Darwin"
    Software: Practice and Experience 2 (Jan-Mar 1972): 93-96.
  • Dewdney, A. K. "In a game called core war hostile programs engage in a battle of bits" Scientific American 250 (May 1984): 14–22.
  • Edgar, Gerald A. "Darwin: A survival game for programmers."
    Computer Language (Apr 1987): 79-86.
  • Levy, Steven Artificial Life: The Quest for a New Creation.
    New York: Pantheon Books, 1992. 317-319.
  • Vyssotsky, Victor A. Darwin: A Game of Survival and (Hopefully) Evolution.
    New Jersey: Bell Telephone Laboratories, 1961.

See Also


Friday, 22 April 2011

Computus: Calculating Easter Sunday

Computus is the algorithm used to calculate the date of Easter. Easter Sunday falls on the first Sunday after the full moon following the Spring equinox. For the purpose of the calculation the full moon is defined as day 14 of the lunar month and the Spring equinox as 20th March.

Unfortunately Computus defies any attempt to render it with beautiful code! This C function roughly follows the assembly language so is a little uglier than strictly necessary:

easter(year, month, date)
int year, *month, *date;
{
    int gold,cent,sa,la,epact,a18,da;
    gold = year%19;
    cent = year/100;
    sa = cent-cent/4;
    la = (8*cent+13)/25;
    epact = (19*gold-sa-la+15)%30;
    a18 = (gold+11*epact)/319;
    da = ((cent%4+year%100/4)*2+a18+32-year%4-epact)%7;
    *month = (90+epact+da-a18)/25;
    *date = (*month+19+epact+da-a18)%32;
}

The algorithm is similar to MaybeGauss1 found in J R Stockton's collection of algorithms for Easter Sunday and is valid for the Gregorian calendar well into the fourth millenium. The algorithm can be adapted to calculate a number of other dates:

  • Shrove Tuesday - 47 days before Easter Sunday
  • First Sunday in Lent - 42 days before
  • Palm Sunday - 7 days before
  • Whit Sunday - 49 days after

Finally here's the same algorithm in 8086 assembly language, length 128 bytes. On entry, AX is the year. On exit AL is the day, AH is the month:

easter:
  push cx
  push dx
  push bx
  push bp
  push si
  push di

  mov bp,ax     ; bp = year (1583:3999) 

  mov cx,100
  cwd
  div cx
  push dx
  xchg si,ax    ; si = century - 1

  mov ax,bp
  mov cl,19
  cwd           
  div cx
  mov bx,dx     ; bx = golden number - 1
  xchg ax,dx

  mul cl
  add ax,15
                ; ax in range (15:357)
  mov dx,si
  add ax,si
  shr dx,1
  shr dx,1
  sub ax,dx
  push ax
  mov ax,8
  mul si
  add ax,13
  mov cl,25
  div cx                      
  xchg dx,ax
  pop ax
  sub ax,dx
  mov cl,30
  cwd
  div cx
  mov di,dx

  mov al,11
  mul dx
  add ax,bx
  mov cl,206    ; multiply by 206 and discard the
  mul cx        ; lower 16 bits of the result.
                ; shorter than dividing by 319

  sub di,dx
  xchg ax,si
  and al,3 
  pop dx
  shr dx,1
  shr dx,1
  add ax,dx
  shl ax,1
  and bp,3
  lea bp,[bp+di-32]
  sub ax,bp
  mov cl,7
  cwd
  div cx
  xchg ax,dx
  add ax,di
  mov bp,ax
  add al,90
  mov cl,25
  div cl
  mov ah,al
  add al,19
  add ax,bp
  and al,31

  pop di
  pop si
  pop bp
  pop bx
  pop dx
  pop cx
  ret

Wednesday, 30 March 2011

Itsy-OS Kernel: Preemptive Switcher & Memory Manager

Itsy-OS v0.1 is a small 8086 operating system kernel providing two basic services: a simple preemptive task switcher and memory management. If necessary, simple IPC and task management can be added to provide the features of a traditional microkernel.

Weighing in at about 380 bytes, Itsy should port well to tiny architectures.

Memory Control Blocks


Each block of memory is preceded by a memory control block which is 32 bytes long. The blocks of memory are arranged as a circular linked list. The first memory control block resides in segment 050h.

org 0h
; -----------------------------
; [Master Memory Control Block]
; -----------------------------

M_NEXT:dw 0             ; address of next MCB
M_LAST:dw 0             ; address of previous MCB
M_PARA:dw 0             ; size of this block in paragraphs including MCB
M_FLAG:db 0             ; flags
       db 0             ;
M_NPRO:dw 0             ; next MCB containing process, zero if not in queue
M_LPRO:dw 0             ; previous MCB containing process, or zero
M_STKP:dw 0             ; stack pointer
M_STKS:dw 0             ; stack segment

M_TIME:dw 0             ; time allocated / de-allocated
M_DATE:dw 0             ; date allocated / de-allocated
M_OWNR:dw 0             ; user number who owns this memory
M_NAME:db '          '  ; name of this memory block

; ---------------------------------------------------------------------------

; flag bits
F_FREE equ 01h          ; zero if this is free memory
F_ACTI equ 02h          ; zero if no task ready for CPU

; ---------------------------------------------------------------------------

  jmp E_INIT            ; setup kernel

; ---------------------------------------------------------------------------

; -------------------
; [Nucleus Data Area]
; -------------------

D_PCP:dw 0              ; segment of current process's MCB
D_SWEN:db 0             ; set to zero when switching disabled

Task Switcher


The task switcher is called by the timer interrupt. First it checks whether switching is disabled. If not:

  • disable switching
  • save the registers of the current task on the stack
  • save the stack pointer of the current task in it's MCB
  • find the next MCB with an available task
  • restore the new task's stack pointer and registers
  • enable switching and transfer control to the new task

; ---------------
; [Task Switcher]
; ---------------

E_SWITCHER:
; test if the switcher is enabled or disabled (indivisible test and set)
  pushf
  push cx
  xor cx,cx
  cs xchg cl,byte[D_SWEN]
  jcxz N_NOSWITCH

; save the registers of the current process
  push ax
  push dx
  push bx
  push bp
  push si
  push di
  push es
  push ds

; save the stack of the current process
  mov di,M_STKP
  cs mov ds,word[di+D_PCP-M_STKP]
  mov word[di],sp     ; M_STKP
  mov word[di+2],ss   ; M_STKS


E_SHORTCUT:

; select an active task to switch to
N_SELTASK:
  mov ds,word[di-4]        ; M_NPRO
  test byte[di-6],F_ACTI   ; M_FLAG
  jz N_SELTASK             ; is this task active?
  cs mov word[di+D_PCP-M_STKP],ds

; restore saved state of process being switched to
  mov sp,word[di]          ; M_STKP
  mov ss,word[di+2]        ; M_STKS
  pop ds
  pop es
  pop di
  pop si
  pop bp
  pop bx
  pop dx
  pop ax
  call E_ENABLE
N_NOSWITCH:
  pop cx
  popf
  iret

Deallocate Memory


Called with DS = MCB of memory to free. Deallocated memory is wiped with 0CCh.

Switching is disabled while the memory structure is being modified. If the memory being deallocated contains a process, it is removed from the process queue. If adjacent memory blocks are marked as free, the blocks are combined.

; -------------------
; [deallocate memory]
; -------------------

E_MEMDEALLOC:

  cs mov byte[D_SWEN],0       ; disable switching

  xor di,di                   ; M_NEXT
  mov ax,word[di+M_NPRO]      ; see if there is entry in process queue
  test ax,ax
  jz N_NOPROC                 ; if there isn't, simply free the memory
  mov es,word[di+M_LPRO]      ; and if there is, remove it!
  es mov word[di+M_NPRO],ax
  mov bx,es
  mov es,ax
  es mov word[di+M_LPRO],bx

  mov ax,ds
  cs cmp ax,word[D_PCP]       ; check if process being killed is the current
  jnz N_NOPROC
  cs mov word[D_PCP],bx       ; if so, set last process as current

  call N_NOPROC               ; free the memory,
  mov di,M_STKP
  jmp short E_SHORTCUT        ; and then afterwards, switch to another task


N_NOPROC:
  mov bp,ds                   ; bp = first paragraph to clear
  mov bx,word[di+M_PARA]      ; bx = number of paragraphs to clear

  mov es,word[di]
  es test byte[di+M_FLAG],F_FREE        ; is next block free?
  jnz N_NNOTJOIN                        ; if not, can't join them

  es mov ax,word[di+M_PARA]             ; get size of next block
  add word[di+M_PARA],ax                ; add to size of this block
  es mov ax,word[di]                    ; move M_NEXT of next...
  mov word[di],ax                       ;  ...to M_NEXT of current
  inc bx                                ; an extra 2 paragraphs to clear
  inc bx
N_NNOTJOIN:
  and byte[di+M_FLAG],0FFh-F_FREE-F_ACTI       ; mark as free

  mov es,word[di+M_LAST]
  es test byte[di+M_FLAG],F_FREE        ; is previous block free?
  jnz N_PNOTJOIN                        ; if not, can't join them

  mov ax,word[di+M_PARA]                ; get size of this block
  es add word[di+M_PARA],ax             ; add to size of previous block
  mov ax,word[di]                       ; move M_NEXT of current...
  es mov word[di],ax                    ;  ... to M_NEXT of previous
  jmp short N_EXTRA2P
                                        ; block already marked as free
N_PNOTJOIN:
  inc bp              ; don't clear MCB
  inc bp
  dec bx
  dec bx

N_EXTRA2P:
  cld                 ; clear memory - bp=location, bx=paragraphs
  mov ax,0CCCCh       ; code for an INT3 instruction to fill memory with
  mov dx,01000h
N_CLRGO:
  mov es,bp
  sub bx,dx
  jc N_CLRFIN
  mov cx,08000h
  rep stosw
  add bp,dx
  jmp short N_CLRGO

N_CLRFIN:
  add bx,dx
  mov cl,3
  shl bx,cl
  mov cx,bx
  rep stosw

E_ENABLE:
  cs inc byte[D_SWEN] ; enable switching
  ret

Allocate Memory


Called with AX = number of paragraphs required. Returns DS = location of memory, or DS = 0 if no memory available. Switching is disabled while the memory structure is being modified. Allocation uses a simple best fit algorithm.

; -----------------
; [allocate memory]
; -----------------

E_MEMALLOC:

  cs mov byte[D_SWEN],0       ; disable switching

  xor di,di
  xor dx,dx                    ; segment of current choice
  xor cx,cx                    ; left-over memory from current choice
  inc ax
  inc ax
  mov bx,050                   ; MMCB

N_MOREMEM:
  mov ds,bx
  test byte[di+M_FLAG],F_FREE  ; is the block we are looking at empty?
  jnz N_WONTFIT                ; if it isn't, move on

  mov bx,word[di+M_PARA]
  sub bx,ax                    ; check size
  jc N_WONTFIT
  jz N_EXACT                   ; perfect fit :-)

; ** KLUDGE ***
  cmp bx,3                     ; if leftover memory block smaller than 3
  jc N_WONTFIT                 ; paragraphs, it would be too small to contain
                               ; a MCB.  Maybe handle this better later

  cmp cx,bx                    ; bx= size of potential leftover memory block
  jc N_WONTFIT                 ; have we found a better fit?
  mov cx,bx
  mov dx,ds                    ; if so, then select it!
N_WONTFIT:
  mov bx,word[di]              ; M_NEXT
  cmp bx,050                   ; are we at MMCB?
  jnz N_MOREMEM

  test dx,dx
  jne N_ALLOCIT
  mov ds,dx                   ; out of memory :-(
  jmp short N_ALEXIT
N_ALLOCIT:
  mov ds,dx
  mov es,word[di]              ; M_NEXT, es= next block

  mov bx,word[di+M_PARA]       ; bx= number of paragraphs for this block
  add bx,dx                    ; bx= end of this block
  sub bx,ax                    ; bx= location of new block's MCB        

  es mov word[di+M_LAST],bx    ; point next block to new block
  mov word[di],bx              ; M_NEXT, point this block to new block
  sub word[di+M_PARA],ax       ; resize this block
  push ds
  mov ds,bx                    ; point es to new block
  pop bx

  mov word[di+M_LAST],bx       ; initialise new block's M_LAST
  mov word[di+M_PARA],ax       ; initialise new block's M_PARA
  mov word[di],es              ; initialise new block's M_NEXT

N_EXACT:
  mov byte[di+M_FLAG],F_FREE   ; mark new block as no longer free
  mov word[di+M_NPRO],di
  mov word[di+M_LPRO],di
N_ALEXIT:
  jmp short E_ENABLE

Setup


Simply sets up the timer interrupt.

E_INT1C:
  call E_SWITCHER
  db 0EAh
D_OLDINT1C:
  dw 0,0

; ---------------------------------------------------------------------------

E_INIT:
  push cs
  pop es
  xor ax,ax
  mov ds,ax
  mov si,01Ch*4
  mov di,D_OLDINT1C
  cld
  push si
  movsw
  movsw
  pop di
  cli
  push ds
  pop es
  mov ax,050h
  stosw
  mov ax,E_INT1C
  stosw
  sti
; ...

Thursday, 17 March 2011

Alternatives to Windows Notepad for Programmers

When I upgraded to Windows 7 I was horrified to discover the text editor I've been using for years no longer works. After suffering Windows Notepad for a few days I set out on a quest to discover the perfect replacement.

My search criteria is pretty basic:

  • can be installed on a memory stick
  • works with UNIX / DOS end-of-line
  • supports syntax highlighting
  • the ability to edit multiple files
  • supports regular expression search
  • requires less than 10MB disk space

After testing a number of free programmer's editors I discovered several which meet (or almost meet) the requirements:


screenshot of ConTEXT programmer's text editor
ConTEXT is a free programmer's text editor. It boasts a number of useful features include the ability to export code to HTML.

(The thumbnail links to a 800×560px screenshot.)

screenshot of Crimson programmer's text editor
Crimson is a source code editor to replace Windows Notepad. Unfortunately the default colour scheme for syntax highlighting doesn't really distinguish between text, delimiters and constants.

screenshot of gedit programmer's text editor
gedit is the text editor from the GNOME desktop enviroment and is also available for Windows. Unfortunately the standard package lacks regex search and it's a heavyweight, weighing in at 65MB+.

screenshot of jEdit programmer's text editor
jEdit is a Java programmer's text editor and has an active community of developers. Hundreds of plugins are available to add a wide range of features. jEdit is another heavyweight, consuming 25MB+ of diskspace.

screenshot of Notepad++ programmer's text editor
Notepad++ is a replacement for Windows Notepad. Features include code folding and support for numerous plugins developed by Notepad++'s active community.

screenshot of Notepad2 programmer's text editor
Notepad2 is a replacement for Windows Notepad that only installs two files. It features a semi-transparent mode allowing users to keep an eye on other programs while editing full screen. Unfortunately Notepad2 can only edit one file at once.

screenshot of Programmer's Notepad text editor
Programmer's Notepad is a programmer's editor with features including code folding, exporting code to HTML and Python scripting. Programmer's Notepad has an active user community.

screenshot of PSPad programmer's text editor
PSPad is a free programmer's editor. The font selector only shows fixed width fonts which is handy, but I'd like to have the option to use a proportional font. PSPad has a feature to export code to HTML. Requires just over 14MB of disk space.

screenshot of SciTE programmer's text editor
SciTE is the demo for the free Scintilla code editing component (used by several editors listed here) and is available as a single file installation. Supports code folding and exporting code to HTML. Unfortunately changing the settings requires the user to poke around in SciTE's config files.


In the end I've settled for Programmer's Notepad. Which editor are you using and what features do you consider essential? :-)

Sunday, 13 March 2011

Efficiency in Forth

I'm busy implementing my own Forth at the moment and it's taking a little longer than anticipated. Each Forth word is a puzzle in itself:

  • What's the least number of words needed to write it?
  • What's the most efficient implementation?

For example, take a look at Implementing MIN in Forth without Conditional Code. The smallest version of MIN is 2 words shorter than eForth's MIN.

Even words with a trivial implementation can pose an interesting problem. For example which of the following is most efficient:

Jones Forth TUCK


: TUCK DUP -ROT ;

Alternative TUCK


: TUCK SWAP OVER ;

If DUP, -ROT, SWAP and OVER are all primitive, the alternative implementation will execute two fewer instructions on an 80x86 Forth. However, -ROT is often implemented in Forth which would cause the Jones Forth TUCK to be substantially slower. Here's a typical implementation of -ROT:

: -ROT SWAP >R SWAP R> ;

If you can think of an alternative two word implementation of TUCK or four word implementation of -ROT, please let me know. :-)