Browse Source

Add missing python tools, update README, and more data from James Bowman website about the Gameduino (still looking for the original Sphynx documentation file)

Godzil 7 years ago
parent
commit
f622dafc8a
100 changed files with 12058 additions and 0 deletions
  1. 13 0
      README.md
  2. BIN
      archives/GameduinoManufacture.zip
  3. BIN
      archives/Gameduino_b0.zip
  4. BIN
      archives/Gameduino_b0m.zip
  5. BIN
      archives/Gameduino_b1m.zip
  6. BIN
      archives/Gameduino_b2m.zip
  7. BIN
      archives/Gameduino_b3m.zip
  8. BIN
      archives/Gameduino_m.zip
  9. 6 0
      archives/README.md
  10. BIN
      archives/files_gameduino.tar.bz2
  11. 61 0
      j0/firmware/basewords.fs
  12. 32 0
      j0/firmware/bgstripes.fs
  13. 91 0
      j0/firmware/cold.fs
  14. 535 0
      j0/firmware/crossj1.fs
  15. 25 0
      j0/firmware/dna.fs
  16. 729 0
      j0/firmware/eforth.fs
  17. 22 0
      j0/firmware/eraser.fs
  18. 18 0
      j0/firmware/flowtest.fs
  19. 22 0
      j0/firmware/helloworld.fs
  20. 69 0
      j0/firmware/hwdefs.fs
  21. 86 0
      j0/firmware/main.fs
  22. 54 0
      j0/firmware/memtest.fs
  23. 546 0
      j0/firmware/nuc.fs
  24. 18 0
      j0/firmware/palcopy.fs
  25. 14 0
      j0/firmware/random.fs
  26. 25 0
      j0/firmware/rasterinterrupt.fs
  27. 19 0
      j0/firmware/regressfreq.fs
  28. 50 0
      j0/firmware/reload.fs
  29. 142 0
      j0/firmware/screens.fs
  30. 24 0
      j0/firmware/selftest1.fs
  31. 31 0
      j0/firmware/setpixel.fs
  32. 17 0
      j0/firmware/showvoices.fs
  33. 33 0
      j0/firmware/soundbuffer.fs
  34. 99 0
      j0/firmware/spectrum.fs
  35. 29 0
      j0/firmware/splitscreen.fs
  36. 13 0
      j0/firmware/spr512.fs
  37. 42 0
      j0/firmware/testflash.fs
  38. 69 0
      j0/firmware/wireframe.fs
  39. 29 0
      j1/firmware/Makefile
  40. 46 0
      j1/firmware/ans.fs
  41. 225 0
      j1/firmware/arp.fs
  42. 60 0
      j1/firmware/basewords.fs
  43. 90 0
      j1/firmware/clock.fs
  44. 527 0
      j1/firmware/crossj1.fs
  45. 70 0
      j1/firmware/defines_tcpip.fs
  46. 94 0
      j1/firmware/defines_tcpip.py
  47. 150 0
      j1/firmware/defines_tcpip2.fs
  48. 215 0
      j1/firmware/defines_tcpip2.py
  49. 176 0
      j1/firmware/dhcp.fs
  50. 81 0
      j1/firmware/dns.fs
  51. 20 0
      j1/firmware/doc.fs
  52. 3 0
      j1/firmware/document.fs
  53. 28 0
      j1/firmware/encode.py
  54. 506 0
      j1/firmware/eth-ax88796.fs
  55. BIN
      j1/firmware/font8x8
  56. BIN
      j1/firmware/fsm-32.png
  57. 11 0
      j1/firmware/genoffsets.py
  58. 16 0
      j1/firmware/go
  59. 57 0
      j1/firmware/hwdefs.fs
  60. 643 0
      j1/firmware/intelhex.py
  61. 362 0
      j1/firmware/invaders.fs
  62. 124 0
      j1/firmware/ip.fs
  63. 70 0
      j1/firmware/ip0.fs
  64. BIN
      j1/firmware/j1.png
  65. 28 0
      j1/firmware/keycodes.fs
  66. 114 0
      j1/firmware/loader.fs
  67. 799 0
      j1/firmware/main.fs
  68. 14 0
      j1/firmware/mkblob.py
  69. 36 0
      j1/firmware/ntp.fs
  70. 546 0
      j1/firmware/nuc.fs
  71. 11 0
      j1/firmware/packet.fs
  72. 434 0
      j1/firmware/ps2kb.fs
  73. 36 0
      j1/firmware/sincos.fs
  74. 20 0
      j1/firmware/sprite.fs
  75. 67 0
      j1/firmware/tftp.fs
  76. 33 0
      j1/firmware/time.fs
  77. 311 0
      j1/firmware/twist.py
  78. 41 0
      j1/firmware/udp.fs
  79. 2 0
      j1/firmware/version.fs
  80. 9 0
      j1/synth/Makefile
  81. 12 0
      j1/synth/j1.bmm
  82. 327 0
      j1/synth/j1.ucf
  83. 174 0
      j1/synth/xilinx.mk
  84. 42 0
      j1/synth/xilinx.opt
  85. 41 0
      j1/verilog/ck_div.v
  86. 187 0
      j1/verilog/j1.v
  87. 36 0
      j1/verilog/rams.v
  88. 667 0
      j1/verilog/top.v
  89. BIN
      python/471fcf9e.png
  90. 8 0
      python/duplicator.py
  91. 1 0
      python/gameduino/__init__.py
  92. 207 0
      python/gameduino/base.py
  93. 174 0
      python/gameduino/compress.py
  94. 498 0
      python/gameduino/prep.py
  95. 48 0
      python/gameduino/registers.py
  96. 130 0
      python/gameduino/remote.py
  97. 274 0
      python/gameduino/sim.py
  98. 4 0
      python/go
  99. BIN
      python/platformer.png
  100. 190 0
      python/randoms.py

+ 13 - 0
README.md

@@ -42,6 +42,19 @@ The adapter is controlled via SPI read/write operations, and looks to the CPU li
 
 [![Poster thumbnail](./doc/images/poster.jpg)](./doc/poster.pdf)
 
+Contents
+--------
+
+You will find here all the data I've collected about the original Gameduino:
+ - board/	contain the schematic and PCB design for the Gameduino
+ - doc/		Documentation about the Gameduino and j1 CPU
+ - fpga/	The FPGA source for the Gameduino
+ - gd/		The Arduino library for the Gameduino
+ - Python/	A set of tool writen in Python
+ - j1/		The original j1 CPU with it's firmware and FPGA source
+ - j0/		The slightly modified j1 CPU for the Gameduino, as the j0 is part of the Gameduino, only the firmware part is accessible here
+ - archives/    Raw files found on James' website
+
 Licensing
 ---------
 

BIN
archives/GameduinoManufacture.zip


BIN
archives/Gameduino_b0.zip


BIN
archives/Gameduino_b0m.zip


BIN
archives/Gameduino_b1m.zip


BIN
archives/Gameduino_b2m.zip


BIN
archives/Gameduino_b3m.zip


BIN
archives/Gameduino_m.zip


+ 6 - 0
archives/README.md

@@ -0,0 +1,6 @@
+Archive Folder
+==============
+
+You will find in this folder all the zip files that you can find on James' website related to the Gameduino.
+
+The files_gameduino.tar.bz2 is an archive of the http://excamera.com/files/gameduino/ folder you can find on James' website

BIN
archives/files_gameduino.tar.bz2


+ 61 - 0
j0/firmware/basewords.fs

@@ -0,0 +1,61 @@
+( Base words implemented in assembler        JCB 13:10 08/24/10)
+
+meta
+: noop      T                       alu ;
+: +         T+N                 d-1 alu ;
+: xor       T^N                 d-1 alu ;
+: and       T&N                 d-1 alu ;
+: or        T|N                 d-1 alu ;
+: invert    ~T                      alu ;
+: =         N==T                d-1 alu ;
+: <         N<T                 d-1 alu ;
+: u<        Nu<T                d-1 alu ;
+: swap      N     T->N              alu ;
+: dup       T     T->N          d+1 alu ;
+: drop      N                   d-1 alu ;
+: over      N     T->N          d+1 alu ;
+: nip       T                   d-1 alu ;
+: >r        N     T->R      r+1 d-1 alu ;
+: r>        rT    T->N      r-1 d+1 alu ;
+: r@        rT    T->N          d+1 alu ;
+: c@        T                       alu
+            [T]                     alu ;
+: c!        T     N->[T]        d-1 alu
+            N                   d-1 alu ;
+: rshift    N>>T                d-1 alu ;
+: *         N*T                 d-1 alu ;
+: swab      swabT                   alu ;
+: 1-        T-1                     alu ;
+: exit      return                      ;
+
+\ Elided words
+\ These words are supported by the hardware but are not
+\ part of ANS Forth.  They are named after the word-pair
+\ that matches their effect  The first word is one of
+\ 2dup, dup or over.  Using these elided words instead of
+\ the pair saves one cycle and one instruction.
+
+: 2dupand   T&N   T->N          d+1 alu ;
+: 2dup<     N<T   T->N          d+1 alu ;
+: 2dup=     N==T  T->N          d+1 alu ;
+: 2dup*     N*T   T->N          d+1 alu ;
+: 2dupor    T|N   T->N          d+1 alu ;
+: 2duprshift N>>T T->N          d+1 alu ;
+: 2dup+     T+N   T->N          d+1 alu ;
+: 2dupu<    Nu<T  T->N          d+1 alu ;
+: 2dupxor   T^N   T->N          d+1 alu ;
+: dup>r     T     T->R          r+1 alu ;
+: dupc@     T     T->N          d+1 alu
+            [T]                     alu ;
+: dupswab   swabT T->N          d+1 alu ;
+: overand   T&N                     alu ;
+: over>     N<T                     alu ;
+: over=     N==T                    alu ;
+: over*     N*T                     alu ;
+: overor    T|N                     alu ;
+: over+     T+N                     alu ;
+: overu>    Nu<T                    alu ;
+: overxor   T^N                     alu ;
+
+: module[ there [char] " parse preserve ;
+: ]module s" Compiled " type count type space there swap - . cr ;

+ 32 - 0
j0/firmware/bgstripes.fs

@@ -0,0 +1,32 @@
+start-microcode bgstripes
+
+\ renders a 64-line horizontal stripe in the BG_COLOR
+\ starting at line COMM+0
+
+\ Interface:
+\ COMM+0    stripe start
+\ 3E80-3EFF 64 color stripe
+
+: 1+    d# 1 + ;
+: -     invert 1+ + ;
+: 0=    d# 0 = ;
+: @     dup c@ swap 1+ c@ swab or ;
+: !     over swab over 1+ c! c! ;
+: 2dup  over over ;
+: min   2dup < ;fallthru
+: ?:    ( xt xf flag -- xt | xf)    \ if flag xt, else xf
+        if drop else nip then ;
+: max   2dup swap < ?: ;
+
+: main
+    begin
+        YLINE c@            \ line COMM+0 is line zero
+        COMM+0 c@ -
+        d# 0 max d# 63 min  \ clamp to 0-63
+        d# 2 * h# 3E80 +    \ index into color table
+        @ BG_COLOR !        \ fetch and write
+    again
+;
+
+end-microcode
+

+ 91 - 0
j0/firmware/cold.fs

@@ -0,0 +1,91 @@
+start-microcode cold
+
+\ system cold start program
+
+\ Interface:
+\ 3400-34FF voices source
+\ 3800-3FFF palette animation source (64 palettes)
+
+h# 3400 constant VOICES_COPY
+h# 3800 constant PALETTES
+
+d# 32   constant PALSZ      \ size of palette in bytes
+
+: vblank@
+        VBLANK ;fallthru
+: _c@   c@ ;                \ these save 1 instruction per use
+: _c!   c! ;
+: 1+    d# 1 + ;
+: @     dup _c@ swap 1+ _c@ swab or ;
+: up1 ( a -- ) \ subtract 1 from sprite coordinate at a
+        dup>r @ dup h# fe00 and swap 1- h# 1FF and or r> ;fallthru
+: !     ( u addr )
+        over swab over 1+ _c! _c! ;
+
+: waitvbi   \ wait for start of vertical blanking interval
+    begin vblank@ 1- until
+    begin vblank@ until ;
+
+: stepfade ( u -- ) \ fade step u is 0-63
+    PALSZ * PALETTES +
+    dup d# 30 + @ BG_COLOR !    \ copy 15th palette entry to BG_COLOR
+    PALETTE16A
+    PALSZ
+;fallthru
+: cmove ( src dst n -- )
+    begin
+        dup
+    while
+        >r
+        over _c@ over _c!
+        1+ swap 1+ swap
+        r> 1-
+    repeat
+    drop ;fallthru
+: 2drop drop drop ;
+
+: endl ( limit u -- limit u' finished ) \ end of loop
+    waitvbi ;fallthru
+: qendl \ quick endl, no wait for frame
+    1+
+    2dup=
+;
+
+: >VOICES ( a -- ) \ load all voices from a
+    VOICES d# 256 cmove ;
+
+[ RAM_SPR 2 + ] constant SPR_YS \ sprite Y coordinates
+
+: main
+    d# 256 d# 0
+    begin
+        dup h# c0 and d# 128 = if
+            dup d# 63 and stepfade
+        then
+        \ copy 3E00+u to VOICES+u
+        dup VOICES_COPY + _c@
+        over VOICES + _c!
+    endl until
+    begin 
+        COMM+9 _c@
+    until
+    h# 3500 >VOICES 
+    d# 265 d# 0
+    begin
+        d# 256 d# 0
+        begin
+            dup d# 4 * SPR_YS + up1
+        qendl until
+        2drop
+        dup SCROLL_Y !
+    endl until
+    h# 3600 >VOICES 
+    d# 0
+    begin
+        waitvbi 
+        dup SCROLL_X !
+        1+
+    again
+;
+
+end-microcode

+ 535 - 0
j0/firmware/crossj1.fs

@@ -0,0 +1,535 @@
+( Cross-compiler for the J1                  JCB 13:12 08/24/10)
+decimal
+
+( outfile is fileid or zero                  JCB 12:30 11/27/10)
+
+0 value outfile
+
+: type ( c-addr u )
+    outfile if
+        outfile write-file throw
+    else
+        type
+    then
+;
+: emit ( u )
+    outfile if
+        pad c! pad 1 outfile write-file throw
+    else
+        emit
+    then
+;
+: cr ( u )
+    outfile if
+        s" " outfile write-line throw
+    else
+        cr
+    then
+;
+: space bl emit ;
+: spaces dup 0> if 0 do space loop then ;
+
+vocabulary j1assembler  \ assembly storage and instructions
+vocabulary metacompiler \ the cross-compiling words
+vocabulary j1target     \ actual target words
+
+: j1asm
+    only
+    metacompiler
+    also j1assembler definitions
+    also forth ;
+: meta
+    only
+    j1target also
+    j1assembler also
+    metacompiler definitions also
+    forth ;
+: target
+    only
+    metacompiler also
+    j1target definitions ;
+
+\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+j1asm
+
+: tcell 2 ;
+: tcells tcell * ;
+: tcell+ tcell + ;
+65536 allocate throw constant tflash
+
+: h#
+    base @ >r 16 base !
+    0. bl parse >number throw 2drop postpone literal
+    r> base ! ; immediate
+
+variable tdp
+: there     tdp @ ;
+: islegal   dup h# 7fff u> abort" illegal address" ;
+: tc!       islegal tflash + c! ;
+: tc@       islegal tflash + c@ ;
+: t!        islegal over h# ff and over tc! swap 8 rshift swap 1+ tc! ;
+: t@        islegal dup tc@ swap 1+ tc@ 8 lshift or ;
+: talign    tdp @ 1 + h# fffe and tdp ! ;
+: tc,       there tc! 1 tdp +! ;
+: t,        there t! tcell tdp +! ;
+: org       tdp ! ;
+
+65536 cells allocate throw constant references
+: referenced cells references + 1 swap +! ;
+
+65536 cells allocate throw constant labels
+: atlabel? ( -- f = are we at a label )
+    labels there cells + @ 0<>
+;
+
+: coldcross
+    tflash 65536 255 fill
+    labels 65536 cells 0 fill
+;
+
+coldcross
+
+: preserve  ( c-addr1 u -- c-addr )
+    dup 1+ allocate throw dup >r
+    2dup c! 1+
+    swap cmove r> ;
+
+: setlabel ( c-addr u -- )
+    atlabel? if 2drop else preserve labels there cells + ! then ;
+
+j1asm
+
+: hex-literal ( u -- c-addr u ) s>d <# bl hold #s [char] $ hold #> ;
+
+: imm h# 8000 or t, ;
+
+: T         h# 0000 ;
+: N         h# 0100 ;
+: T+N       h# 0200 ;
+: T&N       h# 0300 ;
+: T|N       h# 0400 ;
+: T^N       h# 0500 ;
+: ~T        h# 0600 ;
+: N==T      h# 0700 ;
+: N<T       h# 0800 ;
+: N>>T      h# 0900 ;
+: T-1       h# 0a00 ;
+: rT        h# 0b00 ;
+: [T]       h# 0c00 ;
+: N*T       h# 0d00 ;
+: swabT     h# 0e00 ;
+: Nu<T      h# 0f00 ;
+
+: T->N      h# 0080 or ;
+: T->R      h# 0040 or ;
+: N->[T]    h# 0020 or ;
+: d-1       h# 0003 or ;
+: d+1       h# 0001 or ;
+: r-1       h# 000c or ;
+: r-2       h# 0008 or ;
+: r+1       h# 0004 or ;
+
+: alu       h# 6000 or t, ;
+
+: return    T  h# 1000 or r-1 alu ;
+: ubranch   2/ h# 0000 or t, ;
+: 0branch   2/ h# 2000 or t, ;
+: scall     2/ h# 4000 or t, ;
+
+: dump-words ( c-addr n -- ) \ Write n/2 words from c-addr
+    dup 6 > abort" invalid byte count"
+    2/ dup >r
+    0 do
+        dup t@ s>d <# # # # # #> type space
+        2 +
+    loop drop
+    3 r> - 5 * spaces
+;
+
+variable padc
+: pad+ ( c-addr u -- ) \ append to pad
+    dup >r
+    pad padc @ + swap cmove
+    r> padc +! ;
+
+: pad+loc  ( addr -- )
+    dup cells labels + @ ?dup if
+        nip count pad+
+    else
+        s>d <# #s [char] $ hold #> pad+
+    then
+    s"  " pad+
+;
+
+
+: disassemble-j
+    0 padc !
+    dup t@ h# 8000 and if
+        s" LIT " pad+
+        dup t@ h# 7fff and hex-literal pad+ exit
+    else
+        dup t@ h# e000 and h# 6000 = if
+            s" ALU " pad+
+            dup t@ pad+loc exit
+        else
+            dup t@ h# e000 and h# 4000 = if
+                s" CALL "
+            else
+                dup t@ h# 2000 and if 
+                    s" 0BRANCH "
+                else
+                    s" BRANCH "
+                then
+            then
+            pad+
+            dup t@ h# 1fff and 2* pad+loc
+        then
+    then
+;
+
+: disassemble-line ( offset -- offset' )
+    dup cells labels + @ ?dup if s" \ " type count type cr then
+    dup s>d <# # # # # #> type space 
+    dup 2 dump-words
+    disassemble-j
+    pad padc @ type
+    2 + 
+    cr
+;
+
+: disassemble-block
+    0 do
+        disassemble-line
+    loop
+    drop
+;
+
+j1asm
+
+\ tcompile is like "STATE": it is true when compiling
+
+variable tcompile
+: tcompile? tcompile @ ;
+: +tcompile tcompile? abort" Already in compilation mode" 1 tcompile !  ;
+: -tcompile 0 tcompile ! ;
+
+: (literal)
+    \ dup $f rshift over $e rshift xor 1 and throw
+    dup h# 8000 and if
+        h# ffff xor recurse
+        ~T alu
+    else
+        h# 8000 or t,
+    then
+
+;
+: (t-constant)
+    tcompile? if
+        (literal)
+    then
+;
+
+meta
+
+\ Find name - without consuming it - and return a counted string
+: wordstr ( "name" -- c-addr u )
+    >in @ >r bl word count r> >in !
+;
+
+
+: literal (literal) ; immediate
+: 2literal swap (literal) (literal) ; immediate
+: call,
+    dup referenced
+    scall
+;
+
+: t:
+    talign
+    wordstr setlabel
+    create
+        there ,
+        +tcompile 
+        947947
+    does>
+        @
+        tcompile? if
+            call,
+        then
+;
+
+: lookback ( offset -- v ) there swap - t@ ;
+: prevcall?  2 lookback h# e000 and h# 4000 = ;
+: call>goto dup t@ h# 1fff and swap t! ;
+: prevsafe?
+    2 lookback h# e000 and h# 6000 =    \ is an ALU
+    2 lookback h# 004c and 0= and ;   \ does not touch RStack
+: alu>return dup t@ h# 1000 or r-1 swap t! ;
+
+: t; 947947 <> if abort" Unstructured" then
+    true if
+        atlabel? invert prevcall? and if
+            there 2 - call>goto
+        else
+            atlabel? invert prevsafe? and if
+                there 2 - alu>return
+            else
+                return
+            then
+        then
+    else
+        return
+    then
+    -tcompile
+;
+
+: t;fallthru 947947 <> if abort" Unstructured" then
+    -tcompile
+;
+
+variable shadow-tcompile
+wordlist constant escape]-wordlist
+escape]-wordlist set-current
+: ] shadow-tcompile @ tcompile ! previous previous ;
+
+meta
+
+: [ 
+    tcompile @ shadow-tcompile !
+    -tcompile get-order forth-wordlist escape]-wordlist rot 2 + set-order
+;
+
+: : t: ;
+: ; t; ;
+: ;fallthru t;fallthru ;
+: , t, ;
+: c, tc, ;
+
+: constant ( n "name" -- ) create , immediate does> @ (t-constant) ;
+
+: ]asm 
+    -tcompile also forth also j1target also j1assembler ;
+: asm[ +tcompile previous previous previous ;
+: code t: ]asm ;
+
+j1asm
+
+: end-code
+    947947 <> if abort" Unstructured" then
+    previous previous previous ;
+
+meta
+
+\ Some Forth words are safe to use in target mode, so import them
+
+: ( postpone ( ;
+: \ postpone \ ;
+
+: import ( "name" -- )
+    >in @ ' swap >in !
+    create , does> @ execute ;
+
+import meta
+import org
+import include
+import included
+import marker
+import [if]
+import [else]
+import [then]
+
+: do-number ( n -- |n )
+    state @ if
+        postpone literal
+    else
+        tcompile? if
+            (literal)
+        then
+    then
+;
+
+decimal
+
+: [char] ( "name" -- ) ( run: -- ascii) char (literal) ;
+
+: ['] ( "name" -- ) ( run: -- xt )
+    ' tcompile @ >r -tcompile execute r> tcompile !
+    dup referenced
+    (literal)
+;
+
+: (sliteral--h) ( addr n -- ptr ) ( run: -- eeaddr n )
+    s" sliteral" evaluate
+    there >r
+    dup tc,
+    0 do count tc, loop
+    drop
+    talign
+    r>
+;
+
+: (sliteral) (sliteral--h) drop ;
+: s" ( "ccc<quote>" -- ) ( run: -- eaddr n ) [char] " parse (sliteral) ;
+: s' ( "ccc<quote>" -- ) ( run: -- eaddr n ) [char] ' parse (sliteral) ;
+
+: create
+    wordstr setlabel
+    create  there ,
+    does>   @ do-number
+;
+
+: allot     tdp +! ;
+
+: variable  wordstr setlabel create there , 0 t,
+            does> @ do-number ;
+: 2variable  wordstr setlabel create there , 0 t, 0 t,
+            does> @ do-number ;
+
+: createdoes
+    wordstr setlabel
+    create there , ' ,
+    does> dup @ dup referenced (literal) cell+ @ execute
+;
+
+: jumptable 
+    wordstr setlabel
+    create there ,
+    does> s" 2*" evaluate @ dup referenced (literal) s" + @" evaluate
+;
+
+: | ' execute dup referenced t, ;
+
+: ', ' execute t, ;
+
+( DEFER                                      JCB 11:18 11/12/10)
+
+: defer
+    wordstr setlabel
+    create there , 0 t,
+    does> @ tcompile? if do-number s" @ execute" evaluate then ;
+
+: is ( xt "name" -- )
+    tcompile? if
+        ' >body @ do-number
+        s" ! " evaluate
+    else
+        ' execute t!
+    then ;
+
+: ' ' execute ;
+
+( VALUE                                      JCB 13:06 11/12/10)
+
+: value
+    wordstr setlabel
+    create there , t,
+    does> @ do-number s" @" evaluate ;
+
+: to ( u "name" -- )
+    ' >body @ do-number s" !" evaluate ;
+
+( ARRAY                                      JCB 13:34 11/12/10)
+
+: array
+    wordstr setlabel
+    create there , 0 do 0 t, loop
+    does> s" cells" evaluate @ do-number s" +" evaluate ;
+: 2array
+    wordstr setlabel
+    create there , 2* 0 do 0 t, loop
+    does> s" 2* cells" evaluate @ do-number s" +" evaluate ;
+
+( eforth's way of handling constants         JCB 13:12 09/03/10)
+
+: label: ( "name" -- ) create there , immediate does> @ (t-constant) ;
+
+: sign>number
+    over c@ [char] - = if
+        1- swap 1+ swap
+        >number
+        2swap dnegate 2swap
+    else
+        >number
+    then
+;
+
+: base>number ( caddr u base -- )
+    base @ >r base !
+    sign>number
+    r> base !
+    dup 0= if
+        2drop drop do-number
+    else
+        1 = swap c@ [char] . = and if
+            drop dup do-number 16 rshift do-number
+        else
+            -1 abort" bad number"
+        then
+    then ;
+
+: d# 0. bl parse 10 base>number ;
+: h# 0. bl parse 16 base>number ;
+
+( Conditionals                               JCB 13:12 09/03/10)
+: if
+    there
+    0 0branch
+;
+
+: resolve
+    dup t@ there 2/ or swap t!
+;
+
+: then
+    resolve
+    s" (then)" setlabel
+;
+
+: else
+    there
+    0 ubranch 
+    swap resolve
+    s" (else)" setlabel
+;
+
+
+: begin s" (begin)" setlabel there ;
+: again 
+    ubranch
+;
+: until
+    0branch
+;
+: while
+    there
+    0 0branch
+;
+: repeat
+    swap ubranch
+    resolve
+    s" (repeat)" setlabel
+;
+
+: 0do    s" >r d# 0 >r"     evaluate there s" (do)" setlabel ;
+: do     s" 2>r"         evaluate there s" (do)" setlabel ;
+: loop
+    s" looptest" evaluate 0branch
+;
+: i     s" r@" evaluate ;
+
+77 constant sourceline#
+s" none" 2constant sourcefilename
+
+: line# sourceline# (literal) ;
+create currfilename 1 cells 80 + allot
+variable currfilename#
+: savestr ( c-addr u dst -- ) 2dup c! 1+ swap cmove ;
+: getfilename sourcefilename currfilename count compare 0<>
+    if
+        sourcefilename 2dup currfilename savestr (sliteral--h) currfilename# !
+    else
+        currfilename# @ dup 1+ (literal) tc@ (literal)
+    then ;
+: snap line# getfilename s" (snap)" evaluate ; immediate
+: assert 0= if line# sourcefilename (sliteral) s" (assert)" evaluate then ; immediate

+ 25 - 0
j0/firmware/dna.fs

@@ -0,0 +1,25 @@
+start-microcode dna
+
+: 1+ d# 1 + ;
+: 2* d# 2 * ;
+
+: dna@      ( -- u )    h# 8018 c@ ;
+: dna!      ( u -- )    h# 8008 c! ;
+: dnaclk    ( u -- )    dup dna! 1+ dna! ;
+: dnaread   ( )         d# 4 dnaclk ;
+: dnashift  ( )         d# 2 dnaclk ;
+: dnabit    ( u -- u )  2* dna@ + dnashift ;
+: dnabyte   ( -- u )    \ read byte from DNA
+    d# 0
+    dnabit dnabit dnabit dnabit
+    dnabit dnabit dnabit dnabit ;
+: main       \ write 7 byte DNA to COMM
+    dnaread dnashift
+    COMM+7 COMM+0
+    begin
+        dnabyte over c!
+        1+ 2dup=
+    until
+    begin again ;
+
+end-microcode

+ 729 - 0
j0/firmware/eforth.fs

@@ -0,0 +1,729 @@
+meta
+0 value _next
+variable _lit
+variable _invert
+variable _equal
+variable _plus
+variable _mul
+variable _rshift
+variable _and
+variable _or
+variable _xor
+variable _<
+variable _u<
+variable _dup
+variable _drop
+variable _swap
+variable _over
+variable _c!
+variable _!
+variable _c@
+variable _@
+variable _>r
+variable _r>
+variable _r@
+variable _branch
+variable _0branch
+
+variable _doconst
+variable _dovar
+variable _docol
+variable _semis
+target
+
+start-microcode eforth
+
+\ Interface:
+\ COMM+0    instruction pointer
+COMM+0 constant IP
+: 1+    d# 1 + ;
+: @     dup c@ swap 1+ c@ swab or ;
+: IP!
+    IP ;fallthru
+: !     over swab over 1+ c! c! ;
+
+: IP@
+    \ COMM+0 c@ COMM+1 c@ swab or ;
+    IP @ ;
+: fetch \ fetch cell from IP, then increment IP
+    IP@ dup d# 2 + IP! @ ;
+
+meta there _lit ! target
+t: _lit
+    drop
+    fetch
+    ;fallthru
+meta there to _next target
+: _next 
+    fetch           \ fetch xt
+    dup 1+ swap     \ stack the args pointer
+    c@ >r ;         \ jump to the code addr
+
+meta
+: def there wordstr evaluate ! t: ;
+: term _next ubranch t;fallthru ;
+target
+
+
+def _doconst
+    @ ;fallthru
+def _dovar
+    term
+
+def _invert  drop invert        term
+def _equal   drop =             term
+def _plus    drop +             term
+def _mul     drop *             term
+def _rshift  drop rshift        term
+def _and     drop and           term
+def _or      drop or            term
+def _xor     drop xor           term
+def _<       drop <             term
+def _u<      drop u<            term
+def _dup     drop dup           term
+def _drop    drop drop          term
+def _swap    drop swap          term
+def _over    drop over          term
+def _c!      drop c!            term
+def _!       drop !             term
+def _c@      drop c@            term
+def _@       drop @             term
+def _>r      drop >r            term
+def _r>      drop r>            term
+def _r@      drop r@            term
+def _branch  drop fetch IP!     term
+def _0branch drop fetch swap if drop else IP! then term
+
+\ start a colon definition: push IP and use args as new IP
+def _docol
+    IP@ >r ;fallthru
+: IP!term
+    IP! term
+
+\ end a colon definition: pop IP
+def _semis
+    drop r> IP!term ;
+
+[ _next ] constant main
+
+end-microcode
+
+meta 0 to outfile
+
+only forth
+also metacompiler
+also forth definitions also
+
+cr cr cr
+4000 value dst
+create dstmem 8000 allot
+
+s" dump.eforth" w/o create-file throw value dump.eforth
+
+: dstc@
+    dstmem + c@ ;
+: dstc!
+    dstmem + c! ;
+: dst!
+    over 8 rshift over 1+ dstc! dstc!  ;
+: c>>
+    dst dstc!
+    dst 1+ to dst ;
+: >>
+    dst dst!
+    dst 2 + to dst ;
+: s>> ( addr u -- )
+    0 do dup c@ c>> 1+ loop drop ;
+
+0 value 'link
+
+\ These definitions go into the gdforth wordlist
+
+vocabulary gdforth
+
+: gdf-define
+    only
+    gdforth definitions
+    also metacompiler
+    also forth
+;
+
+: gdf-use
+    only
+    gdforth definitions
+;
+
+gdf-define
+
+0 value >link
+: dumpmem
+    \ bring vocab pointer up to date
+    dst 2 - >link .s dst!
+    dstmem 4000 + dst 4000 - dump.eforth write-file throw
+;
+
+: meta meta ;
+
+\ name
+\ length
+\ prev
+\ cfa      <--- xt
+\ args
+
+: label
+    wordstr tuck s>> c>>
+    'link >> dst to 'link
+    create dst ,
+    does> @ >> ;
+
+label gdbranch _branch @ c>>
+label gd0branch _0branch @ c>>
+
+: begin dst ;
+: again gdbranch >> ;
+: until gd0branch >> ;
+: if    gd0branch dst 7777 >> ;
+: else  gdbranch dst >r 8888 >> dst swap dst! r> ;
+: then  dst swap dst! ;
+: while gd0branch dst 7777 >> ;
+: repeat swap gdbranch >> dst swap dst! ;
+
+label (lit) _lit @ c>>
+label invert _invert @ c>>
+label =     _equal @ c>>
+label +     _plus @ c>>
+label *     _mul @ c>>
+label rshift _rshift @ c>>
+label and   _and @ c>>
+label or    _or @ c>>
+label xor   _xor @ c>>
+label <   _< @ c>>
+label u<   _u< @ c>>
+label c!    _c!   @ c>>
+label !    _!   @ c>>
+label c@    _c@   @ c>>
+label @    _@   @ c>>
+label >r   _>r  @ c>>
+label r>   _r>  @ c>>
+label r@   _r@  @ c>>
+label dup    _dup   @ c>>
+label drop    _drop   @ c>>
+label swap    _swap   @ c>>
+label over    _over   @ c>>
+label semis _semis @ c>>
+
+: create   label ;
+: constant label _doconst @ c>> >> ;
+: variable label _dovar @ c>> 0 >> ;
+: ivariable label _dovar @ c>> >> ;         \ initialized variable
+: the-link label _dovar @ c>> dst .s to >link 'link >> ;    \ variable init to 'link
+: allot    dst +! ;
+
+: bc-var (lit) _dovar @ >> ;
+: bc-col (lit) _docol @ >> ;
+: bc-const (lit) _doconst @ >> ;
+: bc-var#       _dovar @ 0ff and ;
+: bc-col#       _docol @ 0ff and ;
+: bc-const#     _doconst @ 0ff and ;
+: semis#        ['] semis >body @ ;
+: literal#      ['] (lit) >body @ ;
+: branch#       ['] gdbranch >body @ ;
+: 0branch#      ['] gd0branch >body @ ;
+: '(lit) (lit) (lit) ;
+
+: \ ['] \ execute ;
+: ( ['] ( execute ;
+
+: : label _docol @ c>> ;
+: ; semis ;
+: x; semis ;    \ alternative name for when ; gets overloaded
+: immediate
+    'link 3 - dup dstc@ 80 or swap dstc! ;
+
+: h# (lit) h# >> ;
+: d# (lit) d# >> ;
+: [char] (lit) char >> ;
+
+: fwd4  (lit) dst 4 + >> ;
+
+gdf-use
+
+\ constants used for making code
+semis# constant semis#          \ address of the semis word
+literal# constant literal#      \ address of the literal word
+branch# constant branch#      \ address of the branch word
+0branch# constant 0branch#      \ address of the 0branch word
+
+bc-var# constant bc-var#        \ the code byte for _dovar
+bc-col# constant bc-col#        \ the code byte for _docol
+bc-const# constant bc-const#    \ code byte for _doconst
+
+: 1+ d# 1 + ;
+: 1- d# -1 + ;
+: <> = invert ;
+: 2dup      over over ;
+: 0<    d# 0 < ;
+: tuck  swap over ;
+
+20 constant BL
+0 constant FALSE
+-1 constant TRUE
+
+10 ivariable BASE
+: HEX ( -- )( 6.2.1660 ) D# 16 BASE ! ;
+: DECIMAL ( -- )( 6.1.1170 ) D# 10 BASE ! ;
+
+: NIP ( n1 n2 -- n2 )( 6.2.1930 ( 0x4D ) SWAP DROP ;
+: ROT ( n1 n2 n3 -- n2 n3 n1 )( 6.1.2160 ( 0x4A ) >R SWAP R> SWAP ;
+: 2DROP ( n n -- )( 6.1.0370 ( 0x52 ) DROP DROP ;
+: 2DUP ( n1 n2 -- n1 n2 n1 n2 )( 6.1.0380 ( 0x53 ) OVER OVER ;
+: ?DUP ( n -- n n | 0 )( 6.1.0630 ( 0x50 ) DUP IF DUP THEN ;
+
+: INVERT ( n -- n )( 6.1.1720 ( 0x26 ) D# -1 XOR ;
+
+: NEGATE ( n -- n )( 6.1.1910 ( 0x2C ) INVERT D# 1 + ;
+: - ( n n -- n )( 6.1.0160 ( 0x1F ) NEGATE + ;
+: ABS ( n -- u )( 6.1.0690 ( 0x2D ) DUP 0< IF NEGATE THEN ;
+
+: 0= ( n -- f )( 6.1.0270 ( 0x34 ) D# 0 = ;
+
+: MIN ( n n -- n )( 6.1.1880 ( 0x2E ) 2DUP < IF BEGIN DROP ;
+: MAX ( n n -- n )( 6.1.1870 ( 0x2F ) 2DUP < UNTIL THEN NIP ;
+
+: WITHIN ( u ul uh -- f )( 6.2.2440 ( 0x45 ) OVER - >R - R> U< ;
+
+: 0<> ( n -- f ) d# 0 = invert ;
+
+: UPPER ( c -- C ) \ convert to uppercase ( upc ( 0x81 ) \ bbb
+  \ DUP [CHAR] a h# 7B WITHIN IF BL XOR THEN ;
+  h# 60 over < if h# 5f and then ;
+
+\ -----------------------------------------------------------
+
+2000 constant RAM_PAL
+0 constant tib
+variable >in        \ offset into TIB
+variable tibsz      \ how much space remains
+
+2892 constant dp
+2895 constant BLKRDY
+2896 constant COUT
+2897 constant COUTRDY
+2898 constant CIN
+
+: ser-emit
+    COUT c!
+    d# 1 COUTRDY c!
+    begin
+        COUTRDY c@ 0=
+    until
+;
+
+400 ivariable cursor
+: vid-emit
+    dup d# 10 = if
+        drop cursor @ h# ffc0 and cursor !
+    else
+        dup d# 13 = if
+            drop cursor @ h# 40 + cursor !
+        else
+            cursor @ tuck c! 1+ cursor !
+        then
+    then
+;
+: page
+    d# 4096 d# 0 begin
+        d# 0 over c!
+        1+ 2dup =
+    until 2drop
+    h# 400 cursor !
+;
+
+: emit vid-emit ;
+
+: space bl emit ;
+: cr   d# 13 emit d# 10 emit ;
+
+: hex1 d# 15 and dup d# 10 < if d# 48 else d# 55 then + emit ;
+: hex2
+    dup 
+    d# 4 rshift
+    hex1 hex1
+;
+: hex4
+    dup
+    d# 8 rshift
+    hex2 hex2 ;
+: hex8 hex4 hex4 ;
+: . hex4 space ;
+
+: snap
+    [char] S emit
+    [char] N emit
+    [char] A emit
+    [char] P emit
+    cr
+    hex4 cr
+    hex4 cr
+    hex4 cr
+    hex4 cr
+    hex4 cr
+    hex4 cr
+    hex4 cr
+    hex4 cr
+    begin again
+;
+
+: CHAR+ 1+ ;
+: CHARS ;
+: PAUSE ;
+
+: +! ( n a -- )( 6.1.0130 ( 0x6C ) DUP >R @ + R> ! ;
+: COUNT ( a -- a c )( 6.1.0980 ( 0x84 ) DUP CHAR+ SWAP C@ ;
+: BOUNDS ( a u -- a+u a )( 0xAC ) OVER + SWAP ;
+: /STRING ( ca u n -- ca+n u-n )( 17.6.1.0245 ) SWAP OVER - >R CHARS + R> ;
+: TYPE ( ca u -- )( 6.1.2310 ( 0x90 )
+  PAUSE  CHARS  BOUNDS BEGIN 2DUP XOR WHILE COUNT EMIT REPEAT 2DROP ;
+
+: SAME? ( ca ca u -- f )
+    begin
+        dup
+    while
+        >r
+        over c@ upper over c@ upper <> if
+            r> drop 2drop false ;
+        then
+        1+ swap 1+ swap
+        r> 1-
+    repeat
+    drop 2drop true ;
+
+
+: isimmediate ( xt -- f )
+    d# -3 + c@ h# 80 and 0<> ;
+: name? ( xt -- ca u )
+    d# -3 + dup c@ h# 7f and tuck - swap ;
+: sayword ( xt -- ) 
+    name? type ;
+
+: inch
+    >in @ tib + ;
+: inch+1
+    d# 1 >in +! ;
+
+: execute
+    fwd4 !
+    + ;
+
+: advance
+    d# 1 /string d# 1 >in +! ;
+
+: skipbl ( ca u -- ca u ) \ skip blank chars
+    begin
+        over c@ bl = over 0<> and
+    while
+        advance
+    repeat
+;
+
+: skipnbl ( ca u -- ca u ) \ skip nonblank chars
+    begin
+        over c@ bl <> over 0<> and
+    while
+        advance
+    repeat
+;
+
+variable source/a
+variable source/l
+
+: source ( -- ca u )( 6.1.2216 )
+    source/a @ source/l @ ;
+: source>in 
+    source >in @ /string ;
+
+: parse-word ( -- ca u )
+    source>in
+    skipbl
+    over >r
+    skipnbl
+    drop
+    r> tuck -
+;
+
+
+\ name
+\ length
+\ prev
+\ cfa      <--- xt
+\ args
+
+: here  dp @ ;
+: c,    here c! d# 1 dp +! ;
+: ,     here ! d# 2 dp +! ;
+: s,    begin dup while over c@ c, d# 1 /string repeat 2drop ;
+
+the-link voc
+0 ivariable state
+
+: head, ( "name" -- )
+    parse-word
+    tuck s, c,
+    voc @ , here voc !
+;
+
+: digit ( c -- u )
+  upper [CHAR] 0 - D# 9 OVER <
+  IF D# 7 - DUP D# 10 < OR THEN ;
+
+: 1/string  d# 1 /string ;
+
+: isnumber ( ca u -- f )
+    \ over c@ [char] - = if 1/string then
+    true >r
+    begin
+        dup 
+    while
+        over c@ digit base @ u< r> and >r
+        1/string
+    repeat
+    2drop r>
+;
+
+: asnumber ( ca u -- false | n true )
+    d# 0 >r
+    begin
+        dup
+    while
+        over c@ digit
+        r> base @ * + >r
+        1/string
+    repeat
+    2drop r> true
+;
+
+: words
+    voc @
+    begin
+        dup
+    while
+        dup sayword space
+        d# -2 + @
+    repeat
+    cr
+;
+
+: sfind ( ca u -- xt | ca u 0 )
+    >r
+    voc @
+    begin
+        dup
+    while
+        2dup name?  ( ca xt ca ca u )
+        dup r@ = if
+            SAME? if r> drop nip ; then
+        else
+            2drop drop
+        then
+        d# -2 + @
+    repeat
+    drop r> false
+;
+
+variable (quit)
+
+: interpret
+    begin
+        parse-word
+        dup
+    while
+        sfind ?dup if
+            dup isimmediate state @ 0= or if
+                execute
+            else
+                ,
+            then
+        else
+            2dup isnumber if
+                state @ if
+                    '(lit) ,
+                    asnumber drop
+                    ,
+                else
+                    asnumber drop
+                then
+            else
+                [char] ? emit type (quit) @ execute
+            then
+        then
+    repeat
+    2drop
+;
+
+( Gameduino system constants                 JCB 16:45 04/15/11)
+
+0000 constant RAM_PIC       1000 constant RAM_CHR        
+2000 constant RAM_PAL       2800 constant IDENT          
+2801 constant REV           2802 constant FRAME       
+2803 constant VBLANK        2804 constant SCROLL_X    
+2806 constant SCROLL_Y      2808 constant JK_MODE                   
+280a constant SPR_DISABLE   280b constant SPR_PAGE              
+280c constant IOMODE        280e constant BG_COLOR              
+2810 constant SAMPLE_L      2812 constant SAMPLE_R
+2a00 constant VOICES        2840 constant PALETTE16A     
+2860 constant PALETTE16B    2880 constant PALETTE4A      
+2888 constant PALETTE4B     2890 constant COMM           
+2900 constant COLLISION     2c00 constant J1_CODE        
+3000 constant RAM_SPR       3800 constant RAM_SPRPAL     
+4000 constant RAM_SPRIMG     
+\ screen \ 11
+8016 constant FLASH_MISO
+8018 constant FLASH_MOSI
+801a constant FLASH_SCK
+801c constant FLASH_SSEL
+
+( SPI                                        JCB 16:42 04/15/11)
+
+: off   d# 0 swap c! ;         : on    d# 1 swap c! ;
+: spi-sel       FLASH_SSEL off ;
+: spi-unsel     FLASH_SSEL on ;
+: spi-cold      spi-unsel FLASH_SCK off ;
+: spi-1bit  ( u -- u )      \ single bit via SPI
+    d# 2 *
+    dup d# 8 rshift FLASH_MOSI c!   \ write MSB to MOSI
+    FLASH_SCK on             \ raise clock
+    FLASH_MISO c@ or         \ read MISO into LSB
+    FLASH_SCK off ;          \ drop clock
+: spi-xfer  ( u -- u )
+    spi-1bit spi-1bit spi-1bit spi-1bit
+    spi-1bit spi-1bit spi-1bit spi-1bit ;
+: >spi spi-xfer drop ;
+
+( Atmel flash                                JCB 07:32 04/16/11)
+
+\ http://www.atmel.com/dyn/resources/prod_documents/doc3638.pdf
+: flash-status  spi-sel h# D7 spi-xfer spi-xfer spi-unsel ;
+: flash-ready?  begin flash-status h# 80 and until ;
+: flash-page    ( u -- ) \ 512*(572+u)
+    d# 572 +
+    dup d# 7 rshift >spi
+    d# 2 * >spi
+    d# 0 >spi ;
+: page>flash ( a u -- a' u' )
+    spi-sel
+    h# 82 >spi tuck flash-page
+    d# 264 bounds begin
+        dup c@ >spi
+        1+ 2dup =
+    until drop swap 1+ spi-unsel
+    flash-ready? ;
+: blk>flash ( a u -- )
+    d# 4 * page>flash page>flash page>flash page>flash 2drop ;
+: flash>page ( u -- )
+    spi-sel
+    h# 03 >spi
+    flash-page
+    h# 0 h# 400 bounds begin
+        d# 0 spi-xfer over c!
+        1+ 2dup =
+    until 2drop spi-unsel ;
+
+: interpret0
+    d# 0
+    begin
+        >r d# 0 >in !
+        r@ source/a ! d# 64 source/l ! interpret
+        r> h# 40 +
+        dup h# 400 =
+    until drop
+;
+
+: load
+    d# 4 * flash>page
+    \ d# 1024 d# 0 begin dup c@ emit 1+ 2dup = until
+    interpret0
+;
+
+variable blk
+    
+: key
+    begin CIN c@ ?dup until
+    d# 0 CIN c! ;
+
+: . hex4 ;
+
+: quit
+    begin
+        cr
+        begin
+            d# 127 emit d# -1 cursor +!
+            key dup d# 13 xor
+        while
+            emit
+        repeat
+        drop
+        cursor @ h# ffc0 and 
+        cursor @ h# 003f and
+        space
+        d# 0 >in !
+        source/l ! source/a ! interpret
+        space
+        [char] o emit
+        [char] k emit
+    again
+;
+
+: (
+    source>in
+    begin
+        over c@ [char] ) <>
+    while
+        advance
+    repeat advance 2drop ;
+
+: nucok
+    [char] N emit
+    [char] U emit
+    [char] C emit
+    space
+    [char] O emit
+    [char] K emit
+    cr ;
+
+\ : sec
+\     spi-sel 77 spi-xfer spi-xfer spi-xfer spi-xfer drop
+\     80 begin 0 spi-xfer hex2 space next cr ;
+
+: f;
+    semis# ,
+    d# 0 state ! ; immediate
+
+: :
+    head,
+    bc-col c,
+    d# 1 state !
+;
+
+label main
+    nucok
+    [char] J IOMODE c! spi-cold
+    d# 0 blk !
+    begin
+        begin BLKRDY c@ until
+
+        \ d# 0 blk @ blk>flash d# 1 blk +!
+
+        interpret0
+        d# 0 BLKRDY c!
+    again
+label blkmain
+    nucok
+    [char] J IOMODE c! spi-cold
+    d# 0 begin
+        dup >r load r> 1+
+    again
+label stump
+    main
+
+dumpmem
+meta

+ 22 - 0
j0/firmware/eraser.fs

@@ -0,0 +1,22 @@
+start-microcode eraser
+
+COMM+8 constant mask
+
+: main
+
+    mask c@ >r
+    h# 3FFF h# 7FFF \ RAM_SPRIMG, from top to bottom
+    begin
+        dupc@ r@ and
+        over c!
+        1- 2dup=
+    until
+
+    \ tell host we're done
+    d# 0 COMM+7 c!
+    \ hang
+    begin again
+;
+
+end-microcode
+

+ 18 - 0
j0/firmware/flowtest.fs

@@ -0,0 +1,18 @@
+start-microcode flowtest
+
+: main
+    begin
+        \ wait until COMM+0 is nonzero
+        begin
+            COMM+0 c@
+        until
+
+        \ increment COMM+1
+        COMM+1 c@ d# 1 + COMM+1 c!
+
+        \ write zero to COMM+0, telling host we're done
+        d# 0 COMM+0 c!
+    again
+;
+
+end-microcode

+ 22 - 0
j0/firmware/helloworld.fs

@@ -0,0 +1,22 @@
+start-microcode helloworld
+: 1+ d# 1 + ;
+: writechar ( addr ch -- addr' )
+    over c! 1+ ;
+
+: main
+    d# 512             \ lines are 64 characters, so this is line 8
+    [char] H writechar
+    [char] E writechar
+    [char] L writechar
+    [char] L writechar
+    [char] O writechar
+    1+
+    [char] W writechar
+    [char] O writechar
+    [char] R writechar
+    [char] L writechar
+    [char] D writechar
+    begin again
+;
+
+end-microcode

+ 69 - 0
j0/firmware/hwdefs.fs

@@ -0,0 +1,69 @@
+( Hardware register definitions              JCB 11:36 01/23/11)
+
+h# 0000 constant RAM_PIC        \ Screen Picture, 64 x 64 = 4096 bytes
+h# 1000 constant RAM_CHR        \ Screen Characters, 256 x 16 = 4096 bytes
+h# 2000 constant RAM_PAL        \ Screen Character Palette, 256 x 8 = 2048 bytes
+h# 2800 constant IDENT
+h# 2801 constant REV
+h# 2802 constant FRAME       
+h# 2803 constant VBLANK      
+h# 2804 constant SCROLL_X    
+h# 2805 constant SCROLL_Xhi
+h# 2806 constant SCROLL_Y    
+h# 2807 constant SCROLL_Yhi
+h# 2808 constant JK_MODE     
+h# 2809 constant J1_RESET
+h# 280a constant SPR_DISABLE
+h# 280b constant SPR_PAGE
+h# 280c constant IOMODE
+h# 280e constant BG_COLOR
+h# 2810 constant SAMPLE_Llo
+h# 2811 constant SAMPLE_Lhi
+h# 2812 constant SAMPLE_Rlo
+h# 2813 constant SAMPLE_Rhi
+
+h# 2a00 constant VOICES      
+h# 2840 constant PALETTE16A     \ 16-color palette RAM A, 32 bytes
+h# 2860 constant PALETTE16B     \ 16-color palette RAM B, 32 bytes
+h# 2880 constant PALETTE4A      \ 4-color palette RAM A, 8 bytes
+h# 2888 constant PALETTE4B      \ 4-color palette RAM A, 8 bytes
+h# 2890 constant COMM           \ Communication buffer
+h# 2900 constant COLLISION      \ Collision detection RAM, 256 bytes
+h# 2b00 constant J1_CODE        \ J1 coprocessor microcode RAM
+h# 3000 constant RAM_SPR        \ Sprite Control, 512 x 4 = 2048 bytes
+h# 3800 constant RAM_SPRPAL     \ Sprite Palettes, 4 x 256 = 2048 bytes
+h# 4000 constant RAM_SPRIMG     \ Sprite Image, 64 x 256 = 16384 bytes
+
+[ COMM 0 + ] constant COMM+0
+[ COMM 1 + ] constant COMM+1
+[ COMM 2 + ] constant COMM+2
+[ COMM 3 + ] constant COMM+3
+[ COMM 4 + ] constant COMM+4
+[ COMM 5 + ] constant COMM+5
+[ COMM 6 + ] constant COMM+6
+[ COMM 7 + ] constant COMM+7
+[ COMM 8 + ] constant COMM+8
+[ COMM 9 + ] constant COMM+9
+[ COMM 10 + ] constant COMM+10
+[ COMM 11 + ] constant COMM+11
+[ COMM 12 + ] constant COMM+12
+[ COMM 13 + ] constant COMM+13
+[ COMM 14 + ] constant COMM+14
+[ COMM 15 + ] constant COMM+15
+
+( Locations for coprocessor only             JCB 11:45 02/06/11)
+
+h# 8000 constant YLINE
+h# 8002 constant ICAP_O
+h# 8004 constant ICAP_BUSY
+h# 8006 constant ICAP_PORT      \ see reload.fs for details
+h# 800a constant FREQHZ
+h# 800c constant FREQTICK
+h# 800e constant P2_V
+h# 8010 constant P2_DIR
+h# 8012 constant RANDOM
+h# 8014 constant CLOCK
+h# 8016 constant FLASH_MISO
+h# 8018 constant FLASH_MOSI
+h# 801a constant FLASH_SCK
+h# 801c constant FLASH_SSEL

+ 86 - 0
j0/firmware/main.fs

@@ -0,0 +1,86 @@
+include crossj1.fs
+
+variable filebase
+
+: suffix ( addr u -- addr u ) \ append suffix to basename
+    0 padc !
+    filebase @ count pad+
+    pad+
+    pad padc @
+;
+: create-output-file w/o create-file throw to outfile ;
+: cbyte s" 0x" type s>d <# # # #> type [char] , emit ;
+hex
+variable hiaddr
+: coderange hiaddr @ 2B00 ;
+: dumpall \ dump the target memory in every useful format
+    hex
+
+    \ .lst file is a human-readable disassembly 
+    s" .lst" suffix create-output-file
+    coderange tuck - 2/ disassemble-block
+
+    \ .binbe is a big-endian binary memory dump
+    s" .binbe" suffix create-output-file
+    coderange do i t@ dup 8 rshift emit emit 2 +loop
+
+    \ .binle is a little-endian binary memory dump
+    s" .binle" suffix create-output-file
+    coderange do i t@ dup emit 8 rshift emit 2 +loop
+
+    \ .h is a little-endian memory dump of bytes 2B00-2BFF
+    s" .h" suffix create-output-file
+    s" static PROGMEM prog_uchar " type
+    filebase @ count type
+    s" _code[] = {" type cr
+    coderange do i t@ dup cbyte 8 rshift cbyte cr 2 +loop
+    s" };" type cr
+;
+decimal
+: start-microcode
+    bl parse preserve filebase !
+    s" marker revert h# 2B02 org" evaluate
+    coldcross decimal
+;
+: end-microcode 
+    there hiaddr !
+    s" h# 2B00 org code 0jump main ubranch end-code revert meta" evaluate
+    dumpall
+    s" target" evaluate
+;
+
+meta
+coldcross
+include basewords.fs
+target
+include hwdefs.fs
+
+\ Build all these microcode files:
+
+include memtest.fs
+include helloworld.fs
+include flowtest.fs
+include setpixel.fs
+include wireframe.fs
+include eraser.fs
+include splitscreen.fs
+include selftest1.fs
+include reload.fs
+include palcopy.fs
+include random.fs
+include rasterinterrupt.fs
+include soundbuffer.fs
+include cold.fs
+include testflash.fs
+include thrasher.fs
+include bgstripes.fs
+include dna.fs
+include regressfreq.fs
+include showvoices.fs
+include spectrum.fs
+include fullscreen_bitmap.fs
+include videocopy.fs
+include spr512.fs
+\ include eforth.fs
+
+meta

+ 54 - 0
j0/firmware/memtest.fs

@@ -0,0 +1,54 @@
+start-microcode memtest
+
+32 constant sp
+0 constant false ( 6.2.1485 )
+: true  ( 6.2.2298 ) d# -1 ;
+: 1+    d# 1 + ;
+: rot   >r swap r> swap ;
+: -rot  swap >r swap r> ;
+: 0=    d# 0 = ;
+: tuck  swap over ;
+: 2drop drop drop ;
+: ?dup  dup if dup then ;
+: 2*        d# 2 * ;
+
+: summit
+    h# 0 c@
+    h# 1 c@ +
+    h# 2 c@ +
+    h# 3 c@ +
+    h# 4 c@ +
+    h# 5 c@ +
+    h# 6 c@ +
+    h# 7 c@ +
+    h# 8 c@ +
+    h# 9 c@ +
+    d# 765
+    \ d# 550
+    over xor
+    if
+        h# DEAD begin again
+    else
+        drop
+    then
+;
+
+: move ( c-addr1 c-addr2 u -- )
+    begin
+        >r
+        over noop noop c@ over c!
+        1+ swap 1+ swap
+        r> 1- dup 0=
+    until
+    drop 2drop
+;
+
+: main
+    begin
+        h# 0 h# 16 d# 10 move
+        h# 16 h# 0 d# 10 move
+        summit
+    again
+;
+
+end-microcode

+ 546 - 0
j0/firmware/nuc.fs

@@ -0,0 +1,546 @@
+( Nucleus: ANS Forth core and ext words      JCB 13:11 08/24/10)
+
+module[ nuc"
+
+32 constant sp
+0 constant false ( 6.2.1485 )
+: depth dsp h# ff and ;
+: true  ( 6.2.2298 ) d# -1 ;
+: 1+    d# 1 + ;
+: rot   >r swap r> swap ;
+: -rot  swap >r swap r> ;
+: 0=    d# 0 = ;
+: tuck  swap over ;
+: 2drop drop drop ;
+: ?dup  dup if dup then ;
+
+: split                     ( a m -- a&m a&~m )
+    over                    \ a m a
+    and                     \ a a&m
+    tuck                    \ a&m a a&m
+    xor                     \ a&m a&~m
+;
+
+: merge ( a b m -- m?b:a )
+    >r          \ a b
+    over xor    \ a a^b
+    r> and      \ a (a^b)&m
+    xor         \ ((a^b)&m)^a
+;
+
+: c@    dup @ swap d# 1 and if d# 8 rshift else d# 255 and then ;
+: c!    ( u c-addr )
+        swap h# ff and dup d# 8 lshift or swap
+        tuck dup @ swap         ( c-addr u v c-addr )
+        d# 1 and d# 0 = h# ff xor
+        merge swap !
+;
+: c!be d# 1 xor c! ;
+
+: looptest  ( -- FIN )
+    r>          ( xt )
+    r>          ( xt i )
+    1+
+    r@ over =   ( xt i FIN )
+    dup if
+        nip r> drop
+    else
+        swap >r
+    then        ( xt FIN )
+    swap
+    >r
+;
+
+\ Stack
+: 2dup  over over ;
+: +!    tuck @ + swap ! ;
+
+\ Comparisons
+: <>        = invert ;
+: 0<>       0= invert ;
+: 0<        d# 0 < ;
+: 0>=       0< invert ;
+: 0>        d# 0 ;fallthru
+: >         swap < ;
+: >=        < invert ;
+: <=        > invert ;
+: u>        swap u< ;
+
+\ Arithmetic
+: negate    invert 1+ ;
+: -         negate + ;
+: abs       dup 0< if negate then ;
+: min       2dup < ;fallthru
+: ?:        ( xt xf f -- xt | xf) if drop else nip then ;
+: max       2dup > ?: ;
+code cells end-code
+code addrcells end-code
+: 2*        d# 1 lshift ;
+code cell+ end-code
+code addrcell+ end-code
+: 2+        d# 2 + ;
+: 2-        1- 1- ;
+: 2/        d# 1 rshift ;
+: c+!       tuck c@ + swap c! ;
+
+: count     dup 1+ swap c@ ;
+: /string   dup >r - swap r> + swap ;
+: aligned   1+ h# fffe and ;
+
+: sliteral
+    r>
+    count
+    2dup 
+    +
+    aligned
+;fallthru
+: execute >r ;
+
+: 15down down1 ;fallthru
+: 14down down1 ;fallthru
+: 13down down1 ;fallthru
+: 12down down1 ;fallthru
+: 11down down1 ;fallthru
+: 10down down1 ;fallthru
+: 9down down1 ;fallthru
+: 8down down1 ;fallthru
+: 7down down1 ;fallthru
+: 6down down1 ;fallthru
+: 5down down1 ;fallthru
+: 4down down1 ;fallthru
+: 3down down1 ;fallthru
+: 2down down1 ;fallthru
+: 1down down1 ;fallthru
+: 0down copy ;
+
+: 15up up1     ;fallthru
+: 14up up1     ;fallthru
+: 13up up1     ;fallthru
+: 12up up1     ;fallthru
+: 11up up1     ;fallthru
+: 10up up1     ;fallthru
+: 9up up1     ;fallthru
+: 8up up1     ;fallthru
+: 7up up1     ;fallthru
+: 6up up1     ;fallthru
+: 5up up1     ;fallthru
+: 4up up1     ;fallthru
+: 3up up1     ;fallthru
+: 2up up1     ;fallthru
+: 1up up1     ;fallthru
+: 0up         ;
+
+code pickbody
+    copy    return
+    1down   scall   1up ubranch
+    2down   scall   2up ubranch
+    3down   scall   3up ubranch
+    4down   scall   4up ubranch
+    5down   scall   5up ubranch
+    6down   scall   6up ubranch
+    7down   scall   7up ubranch
+    8down   scall   8up ubranch
+    9down   scall   9up ubranch
+    10down  scall   10up ubranch
+    11down  scall   11up ubranch
+    12down  scall   12up ubranch
+    13down  scall   13up ubranch
+    14down  scall   14up ubranch
+    15down  scall   15up ubranch
+end-code
+
+: pick
+    dup 2* 2* ['] pickbody + execute ;
+
+: swapdown
+    ]asm
+        N     T->N              alu
+        T                   d-1 alu
+    asm[
+;
+: swapdowns
+    swapdown swapdown swapdown swapdown
+    swapdown swapdown swapdown swapdown
+    swapdown swapdown swapdown swapdown
+    swapdown swapdown swapdown swapdown ;fallthru
+: swapdown0 ;
+: roll
+    2*
+    ['] 0up over - >r
+    ['] swapdown0 swap - execute
+;
+
+\ ========================================================================
+\ Double
+\ ========================================================================
+
+: d=                        ( a b c d -- f )
+    >r                      \ a b c
+    rot xor                 \ b a^c
+    swap r> xor             \ a^c b^d
+    or 0=
+;
+
+: 2@                        ( ptr -- lo hi )
+    dup @ swap 2+ @
+;
+
+: 2!                        ( lo hi ptr -- )
+    rot over                \ hi ptr lo ptr
+    ! 2+ !
+;
+
+: 2over >r >r 2dup r> r> ;fallthru
+: 2swap rot >r rot r> ;
+: 2nip rot drop rot drop ;
+: 2rot ( d1 d2 d3 -- d2 d3 d1 ) 2>r 2swap 2r> 2swap ;
+: 2pick
+    2* 1+ dup 1+            \  lo hi ... 2k+1 2k+2
+    pick                    \  lo hi ... 2k+1 lo
+    swap                    \  lo hi ... lo 2k+1
+    pick                    \  lo hi ... lo hi
+;
+
+
+: d+                              ( augend . addend . -- sum . )
+    rot + >r                      ( augend addend)
+    over +                        ( augend sum)
+    dup rot                       ( sum sum augend)
+    u< if                         ( sum)
+        r> 1+
+    else
+        r>
+    then                          ( sum . )
+;
+
+: +h ( u1 u2 -- u1+u2/2**16 )
+    over +     ( a a+b )
+    u> d# 1 and
+;
+
+: +1c   \ one's complement add, as in TCP checksum
+    2dup +h + +
+;
+
+: s>d dup 0< ;
+: d1+ d# 1. d+ ;
+: dnegate
+    invert swap invert swap
+    d1+
+;
+: DABS ( d -- ud ) ( 8.6.1.1160 ) DUP 0< IF DNEGATE THEN ;
+
+: d- dnegate d+ ;
+
+\ Write zero to double
+: dz d# 0 dup rot 2! ;
+
+: dxor              \ ( a b c d -- e f )
+    rot xor         \ a c b^d
+    -rot xor        \ b^d a^c
+    swap
+;
+
+: dand      rot and -rot and swap ;
+: dor       rot or  -rot or  swap ;
+
+: dinvert  invert swap invert swap ;
+: d<            \ ( al ah bl bh -- flag )
+    rot         \ al bl bh ah
+    2dup =
+    if
+        2drop u<
+    else
+        2nip >
+    then
+;
+
+: d> 2swap d< ;
+: d0<= d# 0. ;fallthru
+: d<= d> invert ;
+: d>= d< invert ;
+: d0= or 0= ;
+: d0< d# 0. d< ;
+: d0<> d0= invert ;
+: d<> d= invert ;
+: d2* 2dup d+ ;
+: d2/ dup d# 15 lshift >r 2/ swap 2/ r> or swap ;
+: dmax       2over 2over d< if 2swap then 2drop ;
+
+: d1- d# -1. d+ ;
+
+: d+!                   ( v. addr -- )
+    dup >r
+    2@
+    d+
+    r>
+    2!
+;
+
+: move ( addr1 addr2 u -- )
+    d# 0 do
+        over @ over !
+        2+ swap 2+ swap
+    loop
+    2drop
+;
+
+: cmove ( c-addr1 c-addr2 u -- )
+    d# 0 do
+        over c@ over c!
+        1+ swap 1+ swap
+    loop
+    2drop
+;
+
+: bounds ( a n -- a+n a ) OVER + SWAP ;
+: fill ( c-addr u char -- ) ( 6.1.1540 )
+  >R  bounds
+  BEGIN 2dupxor
+  WHILE R@ OVER C! 1+
+  REPEAT R> DROP 2DROP ;
+
+\ Math
+
+1 [IF]
+create scratch d# 2 allot
+: um*  ( u1 u2 -- ud )
+    scratch !
+    d# 0.
+    d# 16 0do
+        2dup d+
+        rot dup 0< if
+            2* -rot
+            scratch @ d# 0 d+
+        else
+            2* -rot
+        then
+    loop
+    rot drop
+;
+[ELSE]
+: um*   mult_a ! mult_b ! mult_p 2@ ;
+[THEN]
+
+: *         um* drop ;
+: abssgn    ( a b -- |a| |b| negf )
+        2dup xor 0< >r abs swap abs swap r> ;
+
+: m*    abssgn >r um* r> if dnegate then ;
+
+: divstep
+    ( divisor dq hi )
+    2*
+    over 0< if 1+ then
+    swap 2* swap
+    rot                     ( dq hi divisor )
+    2dup >= if
+        tuck                ( dq divisor hi divisor )
+        -
+        swap                ( dq hi divisor )
+        rot 1+              ( hi divisor dq )
+        rot                 ( divisor dq hi )
+    else
+        -rot
+    then
+    ;
+
+: um/mod ( ud u1 -- u2 u3 ) ( 6.1.2370 )
+    -rot 
+    divstep divstep divstep divstep
+    divstep divstep divstep divstep
+    divstep divstep divstep divstep
+    divstep divstep divstep divstep
+    rot drop swap
+;
+
+: /mod  >R S>D R> ;fallthru
+: SM/REM ( d n -- r q ) ( 6.1.2214 ) ( symmetric )
+  OVER >R >R  DABS R@ ABS UM/MOD
+  R> R@ XOR 0< IF NEGATE THEN  R> 0< IF >R NEGATE R> THEN ;
+: /     /mod nip ;
+: mod   /mod drop ;
+: */mod >R M* R> SM/REM ;
+: */    */mod nip ;
+
+: t2* over >r >r d2*
+    r> 2* r> 0< d# 1 and + ;
+
+variable divisor
+: m*/mod
+    divisor !
+    tuck um* 2swap um*   ( hi. lo. )
+                         ( m0 h l m1 )
+    swap >r d# 0 d+ r>   ( m h l )
+    -rot                 ( l m h )
+    d# 32 0do
+        t2*
+        dup divisor @ >= if
+            divisor @ -
+            rot 1+ -rot
+        then
+   loop
+;
+: m*/ m*/mod drop ;
+
+
+\ Numeric output - from eforth
+
+variable base
+variable hld
+create pad 84 allot create pad|
+
+: <# ( -- ) ( 6.1.0490 )( h# 96 ) pad| HLD ! ;
+: DIGIT ( u -- c ) d# 9 OVER < d# 7 AND + [CHAR] 0 + ;
+: HOLD ( c -- ) ( 6.1.1670 ) HLD @ 1- DUP HLD ! C! ;
+
+: # ( d -- d ) ( 6.1.0030 )
+  d# 0 BASE @ UM/MOD >R BASE @ UM/MOD SWAP DIGIT HOLD R> ;
+
+: #S ( d -- d ) ( 6.1.0050 ) BEGIN # 2DUP OR 0= UNTIL ;
+: #> ( d -- a u ) ( 6.1.0040 ) 2DROP HLD @ pad| OVER - ;
+
+: SIGN ( n -- ) ( 6.1.2210 ) 0< IF [CHAR] - HOLD THEN ;
+
+\ hex(int((1<<24) * (115200 / 2400.) / (WB_CLOCK_FREQ / 2400.)))
+\ d# 42000000 constant WB_CLOCK_FREQ
+
+[ 48000000 17 12 */ ] constant WB_CLOCK_FREQ
+
+0 [IF]
+: uartbase
+    [ $100000000. 115200 WB_CLOCK_FREQ m*/ drop $ffffff00 and dup swap 16 rshift ] 2literal
+;
+: emit-uart
+    begin uart_0 @ 0= until
+    s>d
+    uartbase dor
+    uart_1 ! uart_0 !
+;
+[ELSE]
+: emit-uart drop ;
+[THEN]
+
+create 'emit
+meta emit-uart t, target
+
+: emit 'emit @ execute ;
+: cr d# 13 emit d# 10 emit ;
+d# 32 constant bl
+: space bl emit ;
+: spaces    begin dup 0> while space 1- repeat drop ;
+
+: hex1 d# 15 and dup d# 10 < if d# 48 else d# 55 then + emit ;
+: hex2
+    dup 
+    d# 4 rshift
+    hex1 hex1
+;
+: hex4
+    dup
+    d# 8 rshift
+    hex2 hex2 ;
+
+: hex8 hex4 hex4 ;
+
+: type
+    d# 0 do
+        dup c@ emit
+        1+
+    loop
+    drop
+;
+
+: dump
+    ( addr u )
+    0do
+        dup d# 15 and 0= if dup cr hex4 [char] : emit space space then
+        dup c@ hex2 space 1+
+    loop
+    cr drop
+;
+
+: dump16
+    ( addr u )
+    0do
+        dup hex4 [char] : emit space dup @ hex4 cr 2+
+    loop
+    drop
+;
+
+: decimal d# 10 base ! ;
+: hex d# 16 base ! ;
+
+: S.R ( a u n -- ) OVER - SPACES TYPE ;
+: D.R ( d n -- ) ( 8.6.1.1070 ) >R DUP >R DABS <# #S R> SIGN #> R> S.R ;
+: U.R ( u n -- ) ( 6.2.2330 ) d# 0 SWAP D.R ;
+: .R ( n n -- ) ( 6.2.0210 ) >R S>D R> D.R ;
+
+: D. ( d -- ) ( 8.6.1.1060 ) d# 0 D.R SPACE ;
+: U. ( u -- ) ( 6.1.2320 ) d# 0 D. ;
+: . ( n -- ) ( 6.1.0180 ) BASE @ d# 10 XOR IF U. EXIT THEN S>D D. ;
+: ? ( a -- ) ( 15.6.1.0600 ) @ . ;
+
+( Numeric input )
+
+: DIGIT? ( c base -- u f ) ( 0xA3 )
+  >R [CHAR] 0 - D# 9 OVER <
+  IF D# 7 - DUP D# 10 < OR THEN DUP R> U< ;
+
+: >number ( ud a u -- ud a u ) ( 6.1.0570 )
+    begin
+        dup 0= if exit then
+        over c@ base @ digit? if
+            >r 2swap
+            drop base @ um*
+            r> s>d d+ 2swap
+            d# 1 /string >number
+        else
+            drop exit
+        then
+    again
+;
+
+: .s
+    [char] < emit
+    depth dup hex2
+    [char] > emit
+
+    d# 8 min
+    ?dup if
+        0do
+            i pick hex4 space
+        loop
+    then
+;
+
+build-debug? [IF]
+: (assert)
+    s" **** ASSERTION FAILED **** " type
+    ;fallthru
+: (snap)
+    type space
+    s" LINE " type
+    .
+    [char] : emit
+    space
+    .s
+    cr
+;
+[THEN]
+
+\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+: endian dup d# 8 lshift swap d# 8 rshift or ;
+: 2endian endian swap endian ;
+: swab endian ;
+: typepad ( c-addr u w )    over - >r type r> spaces ;
+: even?     d# 1 and 0= ;
+
+\ rise? and fall? act like ! - except that they leave a true
+\ if the value rose or fell, respectively.
+
+: rise?   ( u a -- f ) 2dup @ u> >r ! r> ;
+: fall?   ( u a -- f ) 2dup @ u< >r ! r> ;
+
+]module

+ 18 - 0
j0/firmware/palcopy.fs

@@ -0,0 +1,18 @@
+start-microcode palcopy
+
+: 1+ d# 1 + ;
+
+: main
+    \ Copy RAM_PAL to PALETTE16A
+    RAM_PAL PALETTE16A
+    d# 32
+    begin
+        >r
+        over c@ over c!
+        1+ swap 1+ swap
+        r> 1- d# 0 =
+    until
+    begin again
+;
+
+end-microcode

+ 14 - 0
j0/firmware/random.fs

@@ -0,0 +1,14 @@
+start-microcode random
+
+\ Fill PICTURE and CHARACTER RAM with random numbers
+
+: main
+    d# 0
+    begin
+        RANDOM c@ over c!
+        1-
+        h# 1FFF and
+    again
+;
+
+end-microcode

+ 25 - 0
j0/firmware/rasterinterrupt.fs

@@ -0,0 +1,25 @@
+start-microcode rasterinterrupt
+
+: 1+ d# 1 + ;
+: @     dup c@ swap 1+ c@ swab or ;
+
+\ COMM+0 holds the 16 bit raster line number:
+\   0 is first line of screen
+\ 299 is last visible line of screen
+\ 300 is beginning of vertical blanking
+\
+\ This microprogram loop raises P2 when the raster is below line COMM+0,
+\ so the Arduino can trigger an interrupt
+
+: main
+    d# 0 P2_DIR c!          \ Make P2 an output
+                            \ Drive P2 high when raster is past line COMM+0
+    begin
+        COMM+0 @            \ user value
+        YLINE c@            \ hardware line
+        <                   \ true when hardware line is below user value
+        P2_V c!             \ write bool to P2
+    again
+;
+
+end-microcode

+ 19 - 0
j0/firmware/regressfreq.fs

@@ -0,0 +1,19 @@
+start-microcode regressfreq
+
+\ Reads 16-bit frequency from COMM, generates square
+\ wave at half frequency PIN2
+
+: 1+    d# 1 + ;
+: @     dup c@ swap 1+ c@ swab or ;
+: !     over swab over 1+ c! c! ;
+
+: main
+    d# 0 P2_DIR c!          \ Make P2 an output
+                            \ Drive P2 high when raster is past line COMM+0
+    COMM+0 @ FREQHZ c!
+    begin
+        FREQTICK c@ P2_V c!
+    again
+;
+
+end-microcode

+ 50 - 0
j0/firmware/reload.fs

@@ -0,0 +1,50 @@
+start-microcode reload
+
+\ This short microprogram forces a full chip reset, just like a power-cycle
+
+\ it talks to the Spartan 3A's ICAP interface to cause a full FPGA reload,
+\ as described in
+\ http://www.xilinx.com/support/documentation/user_guides/ug332.pdf page 278
+
+\ ICAP data bus is bit-reversed!
+: rev1 ( a b -- a' b' ) d# 2 * over d# 1 and + swap d# 1 rshift swap ;
+: rev8 d# 0 rev1 rev1 rev1 rev1 rev1 rev1 rev1 rev1 nip ;
+
+\ The ICAP_PORT low 8 bits are the reversed ICAP_I byte.
+\ Bits 8,9,10 are:
+
+h# 100 constant ICAP-CLK        \ 1,0 is a pulse
+h# 200 constant ICAP-CE         \ 0 means select
+h# 400 constant ICAP-WRITE      \ 0 means write
+
+: ICAP!
+    ICAP_PORT c! ;
+
+: >cicap ( v -- )    \ clock byte v into ICAP
+    rev8 dup ICAP! ICAP-CLK or ICAP! ;
+
+: >icap ( v -- ) \ 16-bit ICAP write
+    dup swab >cicap >cicap ;
+
+: icap_reload
+    h# ffff >icap
+    h# aa99 >icap
+    h# 3261 >icap
+    h# 0000 >icap
+    h# 3281 >icap
+    h# 0000 >icap
+
+    h# 30a1 >icap
+    h# 000e >icap
+    h# 2000 >icap
+    h# 2000 >icap \ needs extra NOOP to complete reboot
+;
+
+: main
+    h# 0 ICAP!
+
+    icap_reload
+    begin again
+;
+
+end-microcode

+ 142 - 0
j0/firmware/screens.fs

@@ -0,0 +1,142 @@
+( 00:                                        JCB 08:33 04/24/11)
+: immediate voc @ 3 - dup c@ 80 or swap c! f;
+: ; semis# , 0 state ! f; immediate
+: exit semis# , ; immediate
+: \ source nip >in ! ; immediate
+: allot     dp +! ;
+: create    head, bc-var# c, ;
+: variable  head, bc-var# c, 0 , ;
+: 2variable head, bc-var# c, 0 , 0 , ;
+: constant  head, bc-const# c, , ;
+: compile,  , ;
+: cell+ 2 + ;  : 2* 2 * ; : cells 2* ;
+
+( 01: branching                              JCB 08:15 04/24/11)
+: ahead     branch# , here 7777 , ;
+: 0ahead    0branch# , here 7777 , ;
+: resolve   here swap ! ; \ resolve stacked ref to HERE
+: begin     here ; immediate
+: again     branch# , , ; immediate
+: until     0branch# , , ; immediate
+: while     0ahead ; immediate
+: repeat    swap branch# , , resolve ; immediate
+: if        0ahead ; immediate
+: else      ahead swap resolve ; immediate
+: then      resolve ; immediate
+
+( 02: parse                                  JCB 08:16 04/24/11)
+: parse \ ( char -- ca u )
+    source>in
+    advance
+    over >r
+    rot >r
+    begin
+        over c@ r@ <> over 0<> and
+    while
+        advance
+    repeat
+    r> 2drop
+    r> tuck - 1 >in +!
+;
+
+( 03: compilation                            JCB 08:17 04/24/11)
+: [         0 state ! ; immediate
+: ]         1 state ! ;
+: literal   literal# , , ; immediate
+: char      parse-word drop c@ ;
+: '         parse-word sfind ;
+: [']       literal# , ' , ; immediate
+: postpone
+    parse-word sfind
+    dup isimmediate invert if
+        literal# , , ['] ,
+    then , ; immediate
+: [char]    char postpone literal ; immediate
+: (         [char] ) parse 2drop ; immediate
+: halt      begin again ;  ' halt (quit) !
+
+( 04: debug                                  JCB 08:17 04/24/11)
+: dump 
+    over hex4 bounds
+    begin 2dup xor
+    while space dup c@ hex2 1+
+    repeat 2drop cr ;
+: isxt voc @ begin 2dup = if 2drop true exit then
+    2 - @ dup 0= until nip ;
+: typext dup isxt if name? type else hex4 then ;
+: seelast   [char] : emit space voc @ name? type
+    here voc @ 1+ begin
+        2dup xor
+    while space dup @ typext cell+
+    repeat cr 2drop ;
+
+( 05: strings                                JCB 08:17 04/24/11)
+: (sliteral)
+    r> count 2dup + >r ;
+: s"
+    [char] " parse
+    postpone (sliteral) dup c, s, ; immediate
+: ." postpone s" postpone type ; immediate
+: .( [char] ) parse type cr ; immediate
+: (next)    1- ?dup 0= ;
+: next      postpone (next) postpone until ; immediate
+
+( 06: move                                   JCB 08:18 04/24/11)
+: cmove ( c-addr1 c-addr2 u -- )
+    begin
+        dup
+    while
+        >r over c@ over c!
+        1+ swap 1+ swap
+        r> 1-
+    repeat
+    drop 2drop
+;
+
+( 07: create does>                           JCB 08:18 04/24/11)
+: (create)  r> cell+ ;
+: (does)    r> dup cell+ swap @ >r ;
+: create
+    head, bc-col# c,
+    ['] (create) , 0 , ;
+: does>
+    r> voc @ 1+
+    ['] (does) over ! cell+ ! ;
+: :noname
+    here bc-col# c, ] ;
+
+( 08: welcome                                JCB 08:18 04/24/11)
+\ screen \ 8
+.( gdforth 0.0.1)
+here hex4 cr
+' quit (quit) !
+
+( 09: DNA                                    JCB 08:19 04/24/11)
+: dna@      ( -- u )    8018 c@ ;
+: dna!      ( u -- )    8008 c! ;
+: dnaclk    ( u -- )    dup dna! 1+ dna! ;
+: dnaread   ( )         4 dnaclk ;
+: dnashift  ( )         2 dnaclk ;
+: dnabit    ( u -- u )  2* dna@ + dnashift ;
+: dnabyte   ( -- u )    \ read byte from DNA
+    0 8 begin >r dnabit r> next ;
+: dna       ( ca -- )   \ write 7 byte DNA at ca
+    dnaread dnashift
+    7 begin
+        >r dnabyte over c! 1+ r>
+    next drop ;
+\ 7F00 dna 7F00 7 dump
+( 10: SPI and flash                          JCB 08:19 04/24/11)
+char J IOMODE c!  spi-cold
+\ flash-status hex2 cr
+: showblk ( u -- )
+    spi-sel
+    03 >spi
+    flash-page
+    400 400 bounds begin
+        0 spi-xfer over c!
+        1+ 2dup =
+    until 2drop spi-unsel ;
+\ 0 showblk
+\ here hex4 cr
+quit

+ 24 - 0
j0/firmware/selftest1.fs

@@ -0,0 +1,24 @@
+start-microcode selftest1
+: 1+ d# 1 + ;
+: ! ( u addr )
+    over swab over 1+ c! c! ;
+: d1+
+    swap 1+
+    swap over
+    d# 0 = if
+        1+
+    then
+;
+
+\ increment COMM+0,1,2,3 until COMM+15 goes high
+: main
+    h# 0.
+    begin
+        over COMM+0 !
+        dup COMM+2 !
+        d1+
+        begin COMM+15 c@ until
+    again
+;
+
+end-microcode

+ 31 - 0
j0/firmware/setpixel.fs

@@ -0,0 +1,31 @@
+start-microcode setpixel
+
+: setpixel ( yx -- ) \ set pixel yx to color from COMM+2, about 35 cycles
+    dup>r
+    h# f and
+    r@ d# 4 rshift h# 0ff0 and or
+    r@ h# 30 and swab or
+    RAM_SPRIMG or ( addr )
+    dupc@ ( addr v )
+    h# c0 r> d# 5 rshift h# 6 and rshift dup>r \ mask in R
+    invert and r> COMM+2 c@ and or
+    swap c!
+;
+
+: main
+    begin
+        \ wait until command reg is nonzero
+        begin
+            COMM+2 c@
+        until
+        
+        \ 0 is X, 1 is Y
+        COMM+0 c@ COMM+1 c@ swab or
+        setpixel
+
+        \ tell host we're done
+        d# 0 COMM+2 c!
+    again
+;
+
+end-microcode

+ 17 - 0
j0/firmware/showvoices.fs

@@ -0,0 +1,17 @@
+start-microcode showvoices
+
+\ continuously move sprites 0-63 to match amplitude of the
+\ 64 sound voices.
+
+: main
+    d# 0
+    begin
+        dup d# 4 * VOICES + d# 2 + c@   \ read voice amplitude
+        invert
+        over d# 4 * RAM_SPR + d# 2 + c! \ write as sprite Y coord
+        1- h# 3f and                    \ next voice
+    again
+;
+
+end-microcode
+

+ 33 - 0
j0/firmware/soundbuffer.fs

@@ -0,0 +1,33 @@
+start-microcode soundbuffer
+
+\ Interface:
+\ COMM+0    sound read pointer
+\ 3F00-3FFF sound buffer
+
+\ This microprogram provides a simple sound sample buffer.
+\ It reads 8-bit samples from the buffer at 3F00-3FFF and
+\ writes them to the audio sample registers SAMPLE_L and
+\ SAMPLE_R.
+\ The current buffer read pointer is COMM+0.
+
+h# 3f00 constant BUFFER
+[ 125 50 * ] constant CYCLE \ one cycle of 8KHz in clocks
+
+: 1+    d# 1 + ;
+: -     invert 1+ + ;
+
+: main
+    d# 0        ( when )
+    begin
+        CLOCK c@ over -     \ positive means CLOCK has passed `when`
+        d# 0 < invert if
+            COMM+0 c@ dup
+            h# 3f00 + c@
+            dup SAMPLE_Lhi c! SAMPLE_Rhi c!
+            1+ COMM+0 c!
+            CYCLE +
+        then
+    again
+;
+
+end-microcode

+ 99 - 0
j0/firmware/spectrum.fs

@@ -0,0 +1,99 @@
+start-microcode spectrum
+
+\ Interface:
+\ 4000-57FF Spectrum bitmap
+\ 5800-5AFF Spectrum attributes
+\ 7000 attribute lookup: 256 bytes.  64 colors of (paper, ink)
+\ 7100 pixel stretch, 16 bytes.
+
+: 1+    d# 1 + ;
+: 0=    d# 0 = ;
+: 4*    d# 4 * ;
+: 64mod h# 3f and ;
+
+: copy1 ( src dst -- src' dst' ) \ copy one byte
+    over c@
+    over c!
+    1+
+;fallthru
+: n1+  ( a b -- a+1 b )
+    swap 1+ swap ;
+
+\ copy attrs for line y
+\ dst is RAM_PAL or RAM_PAL+256
+
+: attrcopy ( y -- )
+    dup 4* h# 5800 + swap            ( src y )
+    h# 8 and d# 32 * RAM_PAL +       ( src dst ) 
+    begin
+        over c@ 64mod 4* h# 7000 + swap \ fetch and lookup attribute
+        copy1 copy1 d# 4 + copy1 copy1 nip
+        n1+
+        dup h# ff and 0=
+    until
+    drop drop
+;
+
+: stretch! ( dst a -- dst' ) \ expand 4 bit graphic a, write to dst
+    h# f and
+    h# 7100 + c@
+    over c! 1+
+    ;
+
+: byte ( src dst -- src' dst' )
+    over c@ swap    ( src a dst )
+                    
+    over d# 4 rshift stretch!
+    swap stretch!  ( src dst' )
+    swap h# 100 + swap      \ down 1 line in spectrum video memory
+;
+
+: byte4
+    byte byte byte byte ;
+
+: pixelcopy ( y -- y )
+    dup 64mod 4* h# 4000 +
+    over h# c0 and d# 32 * +    ( y src )
+    begin
+        dup
+        dup 64mod d# 16 * RAM_CHR +
+        byte4 byte4
+        drop drop
+        1+
+        dup h# 1f and 0=
+    until drop
+;
+
+\ Spectrum memory layout is a bit twisted
+\ line 0      4000, 4001, 4002
+\      1      4100, 4101
+\             ...
+\      8      4020
+\             ...
+\      56     40e0, ...             40ff
+\             ...
+\      63     47e0                  47ff
+\      64     4800
+\      65     4900
+\             ...
+\      191    57e0
+
+\ at line  0 can start work on 4020
+\ at line  8 can start work on 4040
+\ at line 16 can start work on 4060
+\         56                   4800
+\
+\ So in general, at line Y can start work on converting from:
+\ 4000 + (((Y+8) & 38) * 4) + (((y+8) & c0) * 32)
+
+: main
+    d# 0
+    begin
+        begin dup d# 48 + YLINE c@ = until
+        d# 8 + h# ff and
+        dup attrcopy
+        pixelcopy
+    again
+;
+
+end-microcode

+ 29 - 0
j0/firmware/splitscreen.fs

@@ -0,0 +1,29 @@
+start-microcode splitscreen
+
+: 1+    d# 1 + ;
+: @     dupc@ swap 1+ c@ swab or ;
+
+: waitline ( u -- ) \ wait until raster is past u
+    begin
+        dup YLINE c@ =
+    until
+    drop
+;
+
+: loadscroll ( a -- ) \ load SCROLL_X,Y from a
+    dup c@ SCROLL_X c! 1+
+    dup c@ SCROLL_Xhi c! 1+
+    dup c@ SCROLL_Y c! 1+
+    c@ dup SCROLL_Yhi c!
+    d# 7 rshift SPR_DISABLE c!
+;
+
+: main
+    begin
+        COMM+4 @  waitline  COMM+6 loadscroll
+        COMM+10 @ waitline  COMM+12 loadscroll
+        d# 300 waitline     COMM+0 loadscroll
+    again
+;
+
+end-microcode

+ 13 - 0
j0/firmware/spr512.fs

@@ -0,0 +1,13 @@
+start-microcode spr512
+
+: main
+    begin
+        d# 150
+        YLINE c@
+        <
+        SPR_PAGE c!
+    again
+;
+
+end-microcode
+

+ 42 - 0
j0/firmware/testflash.fs

@@ -0,0 +1,42 @@
+start-microcode testflash
+
+: off   d# 0 swap c! ;
+: on    d# 1 swap c! ;
+
+: spi-sel       FLASH_SSEL off ;
+: spi-unsel     FLASH_SSEL on ;
+: spi-cold      spi-unsel FLASH_SCK off ;
+
+: spi-1bit  ( u -- u )      \ single bit via SPI
+    d# 2 *
+    dup swab FLASH_MOSI c!   \ write MSB to MOSI
+    FLASH_SCK on             \ raise clock
+    FLASH_MISO c@ or         \ read MISO into LSB
+    FLASH_SCK off ;          \ drop clock
+
+: spi-xfer  ( u -- u )
+    spi-1bit
+    spi-1bit
+    spi-1bit
+    spi-1bit
+    spi-1bit
+    spi-1bit
+    spi-1bit
+    spi-1bit ;
+
+\ See Atmel AT45DB021D datasheet:
+\ http://www.atmel.com/dyn/resources/prod_documents/doc3638.pdf
+
+: main
+    spi-cold
+    spi-sel
+    h# d7 spi-xfer      \ flash read status command
+    spi-xfer            \ send junk, receive status
+    spi-unsel
+
+    COMM+0 c!           \ write status to COMM+0
+
+    begin again         
+;
+
+end-microcode

+ 69 - 0
j0/firmware/wireframe.fs

@@ -0,0 +1,69 @@
+start-microcode wireframe
+
+\ See http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
+
+COMM+0 constant X0
+COMM+1 constant Y0
+COMM+2 constant X1
+COMM+3 constant Y1
+COMM+4 constant steep
+COMM+5 constant deltax
+COMM+6 constant deltay
+COMM+7 constant ystep
+COMM+8 constant color
+
+: setpixel ( yx -- ) \ set pixel yx to color
+    dup>r
+    h# f and
+    r@ d# 4 rshift h# 0ff0 and or
+    r@ h# 30 and swab or
+    RAM_SPRIMG or ( addr )
+    dupc@ ( addr v )
+    color c@ r> d# 5 rshift h# 6 and rshift or
+    swap c!
+;
+
+: negate invert ;fallthru
+: 1+    d# 1 + ;
+: @     dupc@ swap 1+ c@ swab or ;
+: byte  h# ff and ;
+
+: bresenham
+    deltay c@ negate >r     \ keep -deltay on R stack for speed
+    X0 @                    \ load y0x0
+    deltax c@ d# 1 rshift   \ load deltax/1, is error
+
+                    ( y0x0 error )
+    begin
+        over byte X1 c@ xor
+    while
+        over
+        steep c@ if swab then
+        setpixel
+        r@ +                \ error -= deltay
+        dup d# 0 < if
+            deltax c@ +     \ error += deltax
+            ystep c@ swab 1+
+        else
+            d# 1
+        then
+        >r swap r> + swap   \ increment YX
+    repeat
+    r> drop
+;
+
+: main
+    begin
+        \ wait until command reg is nonzero
+        begin
+            ystep c@
+        until
+        
+        bresenham
+
+        \ tell host we're done
+        d# 0 ystep c!
+    again
+;
+
+end-microcode

+ 29 - 0
j1/firmware/Makefile

@@ -0,0 +1,29 @@
+j1.mem j1.bin: *.fs Makefile
+	@echo ': version s" '`svnversion`'" ;' > version.fs
+	date
+	@date +': builddate d# %s. d# %z ;' >> version.fs
+	@gforth -e 'include main.fs bye'
+
+doc: *.fs Makefile
+	gforth -e 'include ../../docforth/docforth.fs s" document.fs" document bye'
+	mkdir -p html
+	mv *.html html
+
+# PRGDIR=$(HOME)/wge100_firmware/trunk/synth/programming_files/latest
+PRGDIR=../hardware/synth/programming_files/latest
+
+wge100_ip_camera.bit: $(PRGDIR)/wge100.bit j1.mem $(PRGDIR)/wge100_bd.bmm
+	(. /opt/Xilinx/11.1/ISE/settings32.sh ; data2mem -bm $(PRGDIR)/wge100_bd.bmm -bd j1.mem tag jram -bt $(PRGDIR)/wge100.bit -o b wge100_ip_camera.bit )
+
+wge100_ip_camera.mcs: wge100_ip_camera.bit
+	(. /opt/Xilinx/11.1/ISE/settings32.sh ; linux32 promgen -w -p mcs -c FF -o wge100_ip_camera.mcs -u 0 wge100_ip_camera.bit >/dev/null )
+
+defines_tcpip.fs defines_tcpip2.fs: genoffsets.py defines*py
+	python genoffsets.py
+
+download: j1.mem
+	./send
+	sudo python listenterminal.py
+
+bundle: j1.bin wge100_ip_camera.mcs
+	cp j1.bin wge100_ip_camera.mcs tools/*.py $(HOME)/bundle

+ 46 - 0
j1/firmware/ans.fs

@@ -0,0 +1,46 @@
+( Main file for pure ANS forth               JCB 13:53 11/27/10)
+
+: parse-word
+    bl word count ;
+
+: defer create                    ( "name" -- )
+    ['] abort ,  does> @ execute ;
+
+: include                         ( "filename" -- )
+    bl word count included  decimal ;
+
+: is                              ( xt "name" -- )
+    '                               ( xt xt2)
+    state @ if
+        postpone literal  postpone >body  postpone !
+    else
+        >body !
+    then ; immediate
+
+
+: include                         ( "filename" -- )
+    bl parse included  decimal ;
+
+    : Do-Vocabulary                   ( -- )
+        DOES>  @ >R                     ( )( R: widnew)
+            GET-ORDER  SWAP DROP        ( wid_n ... wid_2 n)
+        R> SWAP SET-ORDER ;
+
+: VOCABULARY                      ( "name" -- )
+    WORDLIST CREATE ,  Do-Vocabulary ;
+
+: -rot      rot rot ;
+: nstime     0. ;
+: <=        > invert ;
+: >=        < invert ;
+: d0<>      d0= invert ;
+
+: f>        fswap f< ;
+: f<=       f> invert ;
+: f>=       f< invert ;
+: f=        0e0 f~ ;
+: f<>       f= invert ;
+
+3.1415926e0 fconstant pi
+
+include main.fs

+ 225 - 0
j1/firmware/arp.fs

@@ -0,0 +1,225 @@
+( ARP: Address Resolution Protocol           JCB 13:12 08/24/10)
+module[ arp"
+
+\  ARP uses a small cache of entries.  Each entry has an age counter; new
+\  entries have an age of 0, any entry with an age >N is old.
+\ 
+
+
+d# 12 constant arp-cache-entry-size
+d# 5 constant arp-cache-entries
+TARGET? [IF]
+    meta
+    arp-cache-entry-size arp-cache-entries * d# 64 max
+    target
+    constant arp-size
+    create arp-cache arp-size allot
+    meta
+    arp-cache-entries 1- arp-cache-entry-size * arp-cache +
+    target
+    constant arp-cache-last
+[ELSE]
+    arp-cache-entry-size arp-cache-entries * d# 64 max constant arp-size
+    create arp-cache arp-size allot
+    arp-cache-entries 1- arp-cache-entry-size * arp-cache + constant arp-cache-last
+[THEN]
+
+: arp-foreach                       \  (func -- )
+    arp-cache-last 2>r
+    begin
+        2r@ swap            \  ptr func
+        execute
+        r> dup arp-cache-entry-size - >r
+        arp-cache =
+    until
+    2r> 2drop
+;
+
+build-debug? [IF]
+: arp-.
+    dup @ hex4 space              \  age
+    dup 2+ dup @ swap d# 2 + dup @ swap d# 2 + @ ethaddr-pretty space
+    d# 8 + 2@ ip-pretty
+    cr
+;
+
+: arp-dump
+    ['] arp-. arp-foreach
+;
+[THEN]
+
+: arp-del   h# ff swap !  ;
+: arp-reset ['] arp-del arp-foreach ;
+: used?     @ h# ff <> ;
+: arp-age-1 dup used? d# 1 and swap +!  ;
+: arp-age   ['] arp-age-1 arp-foreach ;
+: arp-cmp   ( ptr0 ptr1 -- ptr) over @ over @ > ?: ;
+: arp-oldest \  return the address of the oldest ARP entry
+    arp-cache ['] arp-cmp arp-foreach ;
+
+\  ARP offsets
+\  d# 28 sender ethaddr
+\  d# 34 sender ip
+\  d# 38 target ethaddr
+\  d# 44 target ip
+
+d# 20 constant OFFSET_ARP_OPCODE
+d# 22 constant OFFSET_ARP_SRC_ETH
+d# 28 constant OFFSET_ARP_SRC_IP
+d# 32 constant OFFSET_ARP_DST_ETH
+d# 38 constant OFFSET_ARP_DST_IP
+
+: arp-is-response
+    OFFSET_ETH_TYPE packet@ h# 806 =
+    OFFSET_ARP_OPCODE packet@ d# 2 =
+    and
+;
+
+\  write the current arp response into the cache, replacing the oldest entry
+: !--                   \  ( val ptr -- ptr-2 )
+    tuck                \  ptr val ptr
+    !
+    2-
+;
+
+\  Current packet is an ARP response; write it to the given slot in the ARP cache, ageing all others
+
+: arp-cache-write   \  ( ptr -- )
+    arp-age         \  because this new entry will have age d# 0
+    d# 0 over !        \  age d# 0
+    >r
+
+    d# 3 OFFSET_ARP_SRC_ETH mac-inoffset mac@n 
+    r@ d# 6 + !-- !-- !-- drop
+    d# 2 OFFSET_ARP_SRC_IP mac-inoffset mac@n 
+    r> d# 8 + 2!
+
+;
+
+\  Comparison of IP
+: arp-cmpip         \  (ip01 ip23 ptr/0 ptr -- ip01 ip23 ptr)
+    dup used? if
+        dup d# 8 + 2@ d# 2 2pick d<> ?:
+    else
+        drop
+    then
+;
+
+: arp-cache-find ( ip01 ip23 -- ip01 ip23 ptr )
+\  Find an IP.  Zero if the IP was not found in the cache, ptr to entry otherwise
+    d# 0 ['] arp-cmpip arp-foreach ;
+
+
+: arp-issue-whohas      \  (ip01 ip23 -- ptr)
+    mac-pkt-begin
+    ethaddr-broadcast mac-pkt-3,
+    net-my-mac mac-pkt-3,
+    h# 806                   \  frame type
+    d# 1                       \  hard type
+    h# 800                   \  prot type
+    mac-pkt-3,
+    h# 0604                  \  hard size, prot size
+    d# 1                       \  op (1=request)
+    mac-pkt-2,
+    net-my-mac mac-pkt-3,
+    net-my-ip mac-pkt-2,
+    ethaddr-broadcast mac-pkt-3,
+    mac-pkt-2,
+    mac-pkt-complete drop
+    mac-send
+;
+
+\  Look up ethaddr for given IP.
+\  If found, return pointer to the 6-byte ethaddr
+\  If not found, issue an ARP request and return d# 0.
+
+: arp-lookup    \  ( ip01 ip23 -- ptr)
+    2dup 
+    ip-router 2@ dxor ip-subnetmask 2@ dand
+    d0<>
+    if
+        2drop
+        ip-router 2@
+    then
+    arp-cache-find          \  ip01 ip23 ptr
+    dup 0= if
+        -rot                \  d# 0 ip01 ip23
+        arp-issue-whohas    \  d# 0
+    else
+        nip nip 2+          \  ptr
+    then
+;
+
+\  If the current packet is an ARP request for our IP, answer it
+: arp-responder
+    \  is destination ff:ff:ff:ff:ff:ff or my mac
+    d# 3 OFFSET_ETH_DST mac-inoffset mac@n
+    and and invert 0=
+
+    net-my-mac              \  a b c
+    d# 2 OFFSET_ETH_DST 2+ mac-inoffset mac@n
+    d= swap                 \  F a
+    OFFSET_ETH_DST packet@ = and
+
+    or
+    OFFSET_ETH_TYPE packet@ h# 806 = and
+    \  is target IP mine?
+    d# 2 OFFSET_ARP_DST_IP mac-inoffset mac@n net-my-ip d= and
+    if
+        mac-pkt-begin
+
+        d# 3 OFFSET_ARP_SRC_ETH mac-pkt-src
+        net-my-mac mac-pkt-3,
+        h# 806                \  frame type
+        d# 1                  \  hard type
+        h# 800                \  prot type
+        mac-pkt-3,
+        h# 0604               \  hard size, prot size
+        d# 2                  \  op (2=reply)
+        mac-pkt-2,
+        net-my-mac mac-pkt-3,
+        net-my-ip mac-pkt-2,
+        d# 3 OFFSET_ARP_SRC_ETH mac-pkt-src
+        d# 2 OFFSET_ARP_SRC_IP mac-pkt-src
+
+        mac-pkt-complete drop
+        mac-send
+    then
+;
+
+: arp-announce
+    mac-pkt-begin
+
+    ethaddr-broadcast mac-pkt-3,
+    net-my-mac mac-pkt-3,
+    h# 806                \  frame type
+    d# 1                  \  hard type
+    h# 800                \  prot type
+    mac-pkt-3,
+    h# 0604               \  hard size, prot size
+    d# 2                  \  op (2=reply)
+    mac-pkt-2,
+    net-my-mac mac-pkt-3,
+    net-my-ip mac-pkt-2,
+    ethaddr-broadcast mac-pkt-3,
+    net-my-ip mac-pkt-2,
+
+    mac-pkt-complete drop
+    mac-send
+    
+;
+
+: arp-handler
+    arp-responder
+    arp-is-response
+    if
+        d# 2 OFFSET_ARP_SRC_IP mac-inoffset mac@n 
+        arp-cache-find nip nip
+        dup 0= if
+            drop arp-oldest
+        then
+        arp-cache-write
+    then
+;
+
+]module

+ 60 - 0
j1/firmware/basewords.fs

@@ -0,0 +1,60 @@
+( Base words implemented in assembler        JCB 13:10 08/24/10)
+
+meta
+: noop      T                       alu ;
+: +         T+N                 d-1 alu ;
+: xor       T^N                 d-1 alu ;
+: and       T&N                 d-1 alu ;
+: or        T|N                 d-1 alu ;
+: invert    ~T                      alu ;
+: =         N==T                d-1 alu ;
+: <         N<T                 d-1 alu ;
+: u<        Nu<T                d-1 alu ;
+: swap      N     T->N              alu ;
+: dup       T     T->N          d+1 alu ;
+: drop      N                   d-1 alu ;
+: over      N     T->N          d+1 alu ;
+: nip       T                   d-1 alu ;
+: >r        N     T->R      r+1 d-1 alu ;
+: r>        rT    T->N      r-1 d+1 alu ;
+: r@        rT    T->N          d+1 alu ;
+: @         [T]                     alu ;
+: !         T     N->[T]        d-1 alu
+            N                   d-1 alu ;
+: dsp       dsp   T->N          d+1 alu ;
+: lshift    N<<T                d-1 alu ;
+: rshift    N>>T                d-1 alu ;
+: 1-        T-1                     alu ;
+: 2r>       rT    T->N      r-1 d+1 alu
+            rT    T->N      r-1 d+1 alu
+            N     T->N              alu ;
+: 2>r       N     T->N              alu
+            N     T->R      r+1 d-1 alu
+            N     T->R      r+1 d-1 alu ;
+: 2r@       rT    T->N      r-1 d+1 alu
+            rT    T->N      r-1 d+1 alu
+            N     T->N          d+1 alu
+            N     T->N          d+1 alu
+            N     T->R      r+1 d-1 alu
+            N     T->R      r+1 d-1 alu
+            N     T->N              alu ;
+: unloop
+            T               r-1     alu
+            T               r-1     alu ;
+: exit      return ;
+
+\ Elided words
+: dup@      [T]   T->N          d+1 alu ;
+: dup>r     T     T->R          r+1 alu ;
+: 2dupxor   T^N   T->N          d+1 alu ;
+: 2dup=     N==T  T->N          d+1 alu ;
+: !nip      T     N->[T]        d-1 alu ;
+: 2dup!     T     N->[T]            alu ;
+
+\ Words used to implement pick
+: up1       T                   d+1 alu ;
+: down1     T                   d-1 alu ;
+: copy      N                       alu ;
+
+: module[ there [char] " parse preserve ;
+: ]module s" Compiled " type count type space there swap - . cr ;

+ 90 - 0
j1/firmware/clock.fs

@@ -0,0 +1,90 @@
+( Clock                                      JCB 10:54 11/17/10)
+
+variable seconds
+variable minutes
+variable hours
+variable days
+variable months
+variable years
+variable weekday
+
+: show2 ( a -- ) @ s>d <# # # #> type ;
+
+: setdate ( ud -- )
+    [ -8 3600 * ] literal s>d d+
+    d# 1 d# 60 m*/mod seconds !
+    d# 1 d# 60 m*/mod minutes !
+    d# 1 d# 24 m*/mod hours !
+    d# 59. d- \ Days since Mar 1 1900
+    2dup d# 1 d# 7 m*/mod weekday ! 2drop
+    d# 365 um/mod ( days years )
+    dup d# 1900 + years !
+    d# 4 / 1- - \ subtract leaps ( daynum 0-365 )
+    dup d# 5 * d# 308 + d# 153 / d# 2 - months !
+    months @ d# 4 + d# 153 d# 5 */ - d# 122 + days !
+
+    home
+    'emit @ >r
+    ['] vga-bigemit 'emit !
+
+    s" ThuFriSatSunMonTueWed" drop
+    weekday @ d# 3 * + d# 3 type cr
+    s" MarAprMayJunJulAugSepOctNovDecJanFeb" drop
+    months @ d# 3 * + d# 3 type
+    space days @ d# 0 .r cr
+    years @ . cr
+
+    true if
+        hours show2
+        minutes show2
+        seconds show2
+        home
+    then
+
+    r> 'emit !
+;
+
+: setdelay ( ud -- )
+    'emit @ >r
+    ['] vga-emit 'emit !
+    d# 32 d# 0 vga-at-xy
+    s" ntp " type <# # # # [char] . hold #s #> type
+    s"  ms " type
+    r> 'emit !
+;
+
+include ntp.fs
+
+2variable ntp-alarm
+
+: clock-main
+    vga-page
+    d# 1000000. ntp-alarm setalarm
+    begin
+        begin
+            mac-fullness
+        while
+            arp-handler
+            OFFSET_ETH_TYPE packet@ h# 800 =
+            if
+                d# 2 OFFSET_IP_DSTIP mac-inoffset mac@n net-my-ip d=
+                if
+                    icmp-handler
+                then
+                loader-handler
+                ntp-handler
+            then
+
+            depth if .s cr then
+            mac-consume
+        repeat
+
+        ntp-alarm isalarm if
+            ntp-request
+            d# 1000000. ntp-alarm setalarm
+        then
+
+        next?
+    until
+;
+

+ 527 - 0
j1/firmware/crossj1.fs

@@ -0,0 +1,527 @@
+( Cross-compiler for the J1                  JCB 13:12 08/24/10)
+decimal
+
+( outfile is fileid or zero                  JCB 12:30 11/27/10)
+
+0 value outfile
+
+: type ( c-addr u )
+    outfile if
+        outfile write-file throw
+    else
+        type
+    then
+;
+: emit ( u )
+    outfile if
+        pad c! pad 1 outfile write-file throw
+    else
+        emit
+    then
+;
+: cr ( u )
+    outfile if
+        s" " outfile write-line throw
+    else
+        cr
+    then
+;
+: space bl emit ;
+: spaces dup 0> if 0 do space loop then ;
+
+vocabulary j1assembler  \ assembly storage and instructions
+vocabulary metacompiler \ the cross-compiling words
+vocabulary j1target     \ actual target words
+
+: j1asm
+    only
+    metacompiler
+    also j1assembler definitions
+    also forth ;
+: meta
+    only
+    j1target also
+    j1assembler also
+    metacompiler definitions also
+    forth ;
+: target
+    only
+    metacompiler also
+    j1target definitions ;
+
+\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+j1asm
+
+: tcell 2 ;
+: tcells tcell * ;
+: tcell+ tcell + ;
+65536 allocate throw constant tflash
+
+: h#
+    base @ >r 16 base !
+    0. bl parse >number throw 2drop postpone literal
+    r> base ! ; immediate
+
+variable tdp
+: there     tdp @ ;
+: islegal   dup h# 7fff u> abort" illegal address" ;
+: tc!       islegal tflash + c! ;
+: tc@       islegal tflash + c@ ;
+: t!        islegal over h# ff and over tc! swap 8 rshift swap 1+ tc! ;
+: t@        islegal dup tc@ swap 1+ tc@ 8 lshift or ;
+: talign    tdp @ 1 + h# fffe and tdp ! ;
+: tc,       there tc! 1 tdp +! ;
+: t,        there t! tcell tdp +! ;
+: org       tdp ! ;
+
+tflash 65536 255 fill
+
+65536 cells allocate throw constant references
+: referenced cells references + 1 swap +! ;
+
+65536 cells allocate throw constant labels
+labels 65536 cells 0 fill
+: atlabel? ( -- f = are we at a label )
+    labels there cells + @ 0<>
+;
+
+: preserve  ( c-addr1 u -- c-addr )
+    dup 1+ allocate throw dup >r
+    2dup c! 1+
+    swap cmove r> ;
+
+: setlabel ( c-addr u -- )
+    atlabel? if 2drop else preserve labels there cells + ! then ;
+
+j1asm
+
+: hex-literal ( u -- c-addr u ) s>d <# bl hold #s [char] $ hold #> ;
+
+: imm h# 8000 or t, ;
+
+: T         h# 0000 ;
+: N         h# 0100 ;
+: T+N       h# 0200 ;
+: T&N       h# 0300 ;
+: T|N       h# 0400 ;
+: T^N       h# 0500 ;
+: ~T        h# 0600 ;
+: N==T      h# 0700 ;
+: N<T       h# 0800 ;
+: N>>T      h# 0900 ;
+: T-1       h# 0a00 ;
+: rT        h# 0b00 ;
+: [T]       h# 0c00 ;
+: N<<T      h# 0d00 ;
+: dsp       h# 0e00 ;
+: Nu<T      h# 0f00 ;
+
+: T->N      h# 0080 or ;
+: T->R      h# 0040 or ;
+: N->[T]    h# 0020 or ;
+: d-1       h# 0003 or ;
+: d+1       h# 0001 or ;
+: r-1       h# 000c or ;
+: r-2       h# 0008 or ;
+: r+1       h# 0004 or ;
+
+: alu       h# 6000 or t, ;
+
+: return    T  h# 1000 or r-1 alu ;
+: ubranch   2/ h# 0000 or t, ;
+: 0branch   2/ h# 2000 or t, ;
+: scall     2/ h# 4000 or t, ;
+
+: dump-words ( c-addr n -- ) \ Write n/2 words from c-addr
+    dup 6 > abort" invalid byte count"
+    2/ dup >r
+    0 do
+        dup t@ s>d <# # # # # #> type space
+        2 +
+    loop drop
+    3 r> - 5 * spaces
+;
+
+variable padc
+: pad+ ( c-addr u -- ) \ append to pad
+    dup >r
+    pad padc @ + swap cmove
+    r> padc +! ;
+
+: pad+loc  ( addr -- )
+    dup cells labels + @ ?dup if
+        nip count pad+
+    else
+        s>d <# #s [char] $ hold #> pad+
+    then
+    s"  " pad+
+;
+
+
+: disassemble-j
+    0 padc !
+    dup t@ h# 8000 and if
+        s" LIT " pad+
+        dup t@ h# 7fff and hex-literal pad+ exit
+    else
+        dup t@ h# e000 and h# 6000 = if
+            s" ALU " pad+
+            dup t@ pad+loc exit
+        else
+            dup t@ h# e000 and h# 4000 = if
+                s" CALL "
+            else
+                dup t@ h# 2000 and if 
+                    s" 0BRANCH "
+                else
+                    s" BRANCH "
+                then
+            then
+            pad+
+            dup t@ h# 1fff and 2* pad+loc
+        then
+    then
+;
+
+: disassemble-line ( offset -- offset' )
+    dup cells labels + @ ?dup if s" \ " type count type cr then
+    dup s>d <# # # # # #> type space 
+    dup 2 dump-words
+    disassemble-j
+    pad padc @ type
+    2 + 
+    cr
+;
+
+: disassemble-block
+    0 do
+        disassemble-line
+    loop
+    drop
+;
+
+j1asm
+
+\ tcompile is like "STATE": it is true when compiling
+
+variable tcompile
+: tcompile? tcompile @ ;
+: +tcompile tcompile? abort" Already in compilation mode" 1 tcompile !  ;
+: -tcompile 0 tcompile ! ;
+
+: (literal)
+    \ dup $f rshift over $e rshift xor 1 and throw
+    dup h# 8000 and if
+        h# ffff xor recurse
+        ~T alu
+    else
+        h# 8000 or t,
+    then
+
+;
+: (t-constant)
+    tcompile? if
+        (literal)
+    then
+;
+
+meta
+
+\ Find name - without consuming it - and return a counted string
+: wordstr ( "name" -- c-addr u )
+    >in @ >r bl word count r> >in !
+;
+
+
+: literal (literal) ; immediate
+: 2literal swap (literal) (literal) ; immediate
+: call,
+    dup referenced
+    scall
+;
+
+: t:
+    talign
+    wordstr setlabel
+    create
+        there ,
+        +tcompile 
+        947947
+    does>
+        @
+        tcompile? if
+            call,
+        then
+;
+
+: lookback ( offset -- v ) there swap - t@ ;
+: prevcall?  2 lookback h# e000 and h# 4000 = ;
+: call>goto dup t@ h# 1fff and swap t! ;
+: prevsafe?
+    2 lookback h# e000 and h# 6000 =    \ is an ALU
+    2 lookback h# 004c and 0= and ;   \ does not touch RStack
+: alu>return dup t@ h# 1000 or r-1 swap t! ;
+
+: t; 947947 <> if abort" Unstructured" then
+    true if
+        atlabel? invert prevcall? and if
+            there 2 - call>goto
+        else
+            atlabel? invert prevsafe? and if
+                there 2 - alu>return
+            else
+                return
+            then
+        then
+    else
+        return
+    then
+    -tcompile
+;
+
+: t;fallthru 947947 <> if abort" Unstructured" then
+    -tcompile
+;
+
+variable shadow-tcompile
+wordlist constant escape]-wordlist
+escape]-wordlist set-current
+: ] shadow-tcompile @ tcompile ! previous previous ;
+
+meta
+
+: [ 
+    tcompile @ shadow-tcompile !
+    -tcompile get-order forth-wordlist escape]-wordlist rot 2 + set-order
+;
+
+: : t: ;
+: ; t; ;
+: ;fallthru t;fallthru ;
+: , t, ;
+: c, tc, ;
+
+: constant ( n "name" -- ) create , immediate does> @ (t-constant) ;
+
+: ]asm 
+    -tcompile also forth also j1target also j1assembler ;
+: asm[ +tcompile previous previous previous ;
+: code t: ]asm ;
+
+j1asm
+
+: end-code
+    947947 <> if abort" Unstructured" then
+    previous previous previous ;
+
+meta
+
+\ Some Forth words are safe to use in target mode, so import them
+
+: ( postpone ( ;
+: \ postpone \ ;
+
+: import ( "name" -- )
+    >in @ ' swap >in !
+    create , does> @ execute ;
+
+import meta
+import org
+import include
+import [if]
+import [else]
+import [then]
+
+: do-number ( n -- |n )
+    state @ if
+        postpone literal
+    else
+        tcompile? if
+            (literal)
+        then
+    then
+;
+
+decimal
+
+: [char] ( "name" -- ) ( run: -- ascii) char (literal) ;
+
+: ['] ( "name" -- ) ( run: -- xt )
+    ' tcompile @ >r -tcompile execute r> tcompile !
+    dup referenced
+    (literal)
+;
+
+: (sliteral--h) ( addr n -- ptr ) ( run: -- eeaddr n )
+    s" sliteral" evaluate
+    there >r
+    dup tc,
+    0 do count tc, loop
+    drop
+    talign
+    r>
+;
+
+: (sliteral) (sliteral--h) drop ;
+: s" ( "ccc<quote>" -- ) ( run: -- eaddr n ) [char] " parse (sliteral) ;
+: s' ( "ccc<quote>" -- ) ( run: -- eaddr n ) [char] ' parse (sliteral) ;
+
+: create
+    wordstr setlabel
+    create  there ,
+    does>   @ do-number
+;
+
+: allot     tdp +! ;
+
+: variable  wordstr setlabel create there , 0 t,
+            does> @ do-number ;
+: 2variable  wordstr setlabel create there , 0 t, 0 t,
+            does> @ do-number ;
+
+: createdoes
+    wordstr setlabel
+    create there , ' ,
+    does> dup @ dup referenced (literal) cell+ @ execute
+;
+
+: jumptable 
+    wordstr setlabel
+    create there ,
+    does> s" 2*" evaluate @ dup referenced (literal) s" + @" evaluate
+;
+
+: | ' execute dup referenced t, ;
+
+: ', ' execute t, ;
+
+( DEFER                                      JCB 11:18 11/12/10)
+
+: defer
+    wordstr setlabel
+    create there , 0 t,
+    does> @ tcompile? if do-number s" @ execute" evaluate then ;
+
+: is ( xt "name" -- )
+    tcompile? if
+        ' >body @ do-number
+        s" ! " evaluate
+    else
+        ' execute t!
+    then ;
+
+: ' ' execute ;
+
+( VALUE                                      JCB 13:06 11/12/10)
+
+: value
+    wordstr setlabel
+    create there , t,
+    does> @ do-number s" @" evaluate ;
+
+: to ( u "name" -- )
+    ' >body @ do-number s" !" evaluate ;
+
+( ARRAY                                      JCB 13:34 11/12/10)
+
+: array
+    wordstr setlabel
+    create there , 0 do 0 t, loop
+    does> s" cells" evaluate @ do-number s" +" evaluate ;
+: 2array
+    wordstr setlabel
+    create there , 2* 0 do 0 t, loop
+    does> s" 2* cells" evaluate @ do-number s" +" evaluate ;
+
+( eforth's way of handling constants         JCB 13:12 09/03/10)
+
+: sign>number
+    over c@ [char] - = if
+        1- swap 1+ swap
+        >number
+        2swap dnegate 2swap
+    else
+        >number
+    then
+;
+
+: base>number ( caddr u base -- )
+    base @ >r base !
+    sign>number
+    r> base !
+    dup 0= if
+        2drop drop do-number
+    else
+        1 = swap c@ [char] . = and if
+            drop dup do-number 16 rshift do-number
+        else
+            -1 abort" bad number"
+        then
+    then ;
+
+: d# 0. bl parse 10 base>number ;
+: h# 0. bl parse 16 base>number ;
+
+( Conditionals                               JCB 13:12 09/03/10)
+: if
+    there
+    0 0branch
+;
+
+: resolve
+    dup t@ there 2/ or swap t!
+;
+
+: then
+    resolve
+    s" (then)" setlabel
+;
+
+: else
+    there
+    0 ubranch 
+    swap resolve
+    s" (else)" setlabel
+;
+
+
+: begin s" (begin)" setlabel there ;
+: again 
+    ubranch
+;
+: until
+    0branch
+;
+: while
+    there
+    0 0branch
+;
+: repeat
+    swap ubranch
+    resolve
+    s" (repeat)" setlabel
+;
+
+: 0do    s" >r d# 0 >r"     evaluate there s" (do)" setlabel ;
+: do     s" 2>r"         evaluate there s" (do)" setlabel ;
+: loop
+    s" looptest" evaluate 0branch
+;
+: i     s" r@" evaluate ;
+
+77 constant sourceline#
+s" none" 2constant sourcefilename
+
+: line# sourceline# (literal) ;
+create currfilename 1 cells 80 + allot
+variable currfilename#
+: savestr ( c-addr u dst -- ) 2dup c! 1+ swap cmove ;
+: getfilename sourcefilename currfilename count compare 0<>
+    if
+        sourcefilename 2dup currfilename savestr (sliteral--h) currfilename# !
+    else
+        currfilename# @ dup 1+ (literal) tc@ (literal)
+    then ;
+: snap line# getfilename s" (snap)" evaluate ; immediate
+: assert 0= if line# sourcefilename (sliteral) s" (assert)" evaluate then ; immediate

+ 70 - 0
j1/firmware/defines_tcpip.fs

@@ -0,0 +1,70 @@
+42 constant OFFSET_DHCP
+70 constant OFFSET_DHCP_CHADDR
+54 constant OFFSET_DHCP_CIADDR
+150 constant OFFSET_DHCP_FILE
+52 constant OFFSET_DHCP_FLAGS
+66 constant OFFSET_DHCP_GIADDR
+44 constant OFFSET_DHCP_HLEN
+45 constant OFFSET_DHCP_HOPS
+43 constant OFFSET_DHCP_HTYPE
+42 constant OFFSET_DHCP_OP
+278 constant OFFSET_DHCP_OPTIONS
+50 constant OFFSET_DHCP_SECS
+62 constant OFFSET_DHCP_SIADDR
+548 constant OFFSET_DHCP_SIZE
+86 constant OFFSET_DHCP_SNAME
+46 constant OFFSET_DHCP_XID
+58 constant OFFSET_DHCP_YIADDR
+42 constant OFFSET_DNS
+44 constant OFFSET_DNS_FLAGS
+42 constant OFFSET_DNS_IDENTIFICATION
+48 constant OFFSET_DNS_NOA
+52 constant OFFSET_DNS_NOARR
+46 constant OFFSET_DNS_NOQ
+50 constant OFFSET_DNS_NORR
+54 constant OFFSET_DNS_QUERY
+13 constant OFFSET_DNS_SIZE
+0 constant OFFSET_ETH
+0 constant OFFSET_ETH_DST
+14 constant OFFSET_ETH_SIZE
+6 constant OFFSET_ETH_SRC
+12 constant OFFSET_ETH_TYPE
+34 constant OFFSET_ICMP
+36 constant OFFSET_ICMP_CHKSUM
+38 constant OFFSET_ICMP_IDENTIFIER
+40 constant OFFSET_ICMP_SEQUENCE
+8 constant OFFSET_ICMP_SIZE
+34 constant OFFSET_ICMP_TYPECODE
+14 constant OFFSET_IP
+24 constant OFFSET_IP_CHKSUM
+30 constant OFFSET_IP_DSTIP
+18 constant OFFSET_IP_IPID
+20 constant OFFSET_IP_IPOFFSET
+16 constant OFFSET_IP_LENGTH
+20 constant OFFSET_IP_SIZE
+26 constant OFFSET_IP_SRCIP
+22 constant OFFSET_IP_TTLPROTO
+14 constant OFFSET_IP_VHLTOS
+42 constant OFFSET_JUICE
+68 constant OFFSET_JUICE_COMMAND
+42 constant OFFSET_JUICE_HASH
+62 constant OFFSET_JUICE_MAGIC
+70 constant OFFSET_JUICE_PAYLOAD
+66 constant OFFSET_JUICE_SEQ
+30 constant OFFSET_JUICE_SIZE
+34 constant OFFSET_TCP
+42 constant OFFSET_TCP_ACK
+50 constant OFFSET_TCP_CHECKSUM
+36 constant OFFSET_TCP_DESTPORT
+46 constant OFFSET_TCP_FLAGS
+38 constant OFFSET_TCP_SEQNUM
+20 constant OFFSET_TCP_SIZE
+34 constant OFFSET_TCP_SOURCEPORT
+52 constant OFFSET_TCP_URGENT
+48 constant OFFSET_TCP_WINDOW
+34 constant OFFSET_UDP
+40 constant OFFSET_UDP_CHECKSUM
+36 constant OFFSET_UDP_DESTPORT
+38 constant OFFSET_UDP_LENGTH
+8 constant OFFSET_UDP_SIZE
+34 constant OFFSET_UDP_SOURCEPORT

+ 94 - 0
j1/firmware/defines_tcpip.py

@@ -0,0 +1,94 @@
+layout = [
+    ('ETH', [
+        ('DST', 6),
+        ('SRC',  6),
+        ('TYPE', 2),
+        [
+            ('IP', [
+                ('VHLTOS', 2),
+                ('LENGTH', 2),
+                ('IPID', 2),
+                ('IPOFFSET', 2),
+                ('TTLPROTO', 2),
+                ('CHKSUM', 2),
+                ('SRCIP', 4),
+                ('DSTIP', 4),
+                [
+                    ('ICMP', [
+                        ('TYPECODE', 2),
+                        ('CHKSUM', 2),
+                        ('IDENTIFIER', 2),
+                        ('SEQUENCE', 2) ]),
+                    ('TCP', [
+                        ('SOURCEPORT', 2),
+                        ('DESTPORT', 2),
+                        ('SEQNUM', 4),
+                        ('ACK', 4),
+                        ('FLAGS', 2),
+                        ('WINDOW', 2),
+                        ('CHECKSUM', 2),
+                        ('URGENT', 2) ]),
+                    ('UDP', [
+                        ('SOURCEPORT', 2),
+                        ('DESTPORT', 2),
+                        ('LENGTH', 2),
+                        ('CHECKSUM', 2),
+                        [
+                            ('DHCP', [
+                                ('OP', 1),
+                                ('HTYPE', 1),
+                                ('HLEN', 1),
+                                ('HOPS', 1),
+                                ('XID', 4),
+                                ('SECS', 2),
+                                ('FLAGS', 2),
+                                ('CIADDR', 4),
+                                ('YIADDR', 4),
+                                ('SIADDR', 4),
+                                ('GIADDR', 4),
+                                ('CHADDR', 16),
+                                ('SNAME', 64),
+                                ('FILE', 128),
+                                ('OPTIONS', 312)
+                            ]),
+                            ('DNS', [
+                                ('IDENTIFICATION', 2),
+                                ('FLAGS', 2),
+                                ('NOQ', 2),
+                                ('NOA', 2),
+                                ('NORR', 2),
+                                ('NOARR', 2),
+                                ('QUERY', 1)
+                            ]),
+                            ('JUICE', [
+                                ('HASH', 20),
+                                ('MAGIC', 4),
+                                ('SEQ', 2),
+                                ('COMMAND', 2),
+                                ('PAYLOAD', 2)
+                            ])
+                        ]
+                    ])
+                ]
+            ])
+        ]])
+]
+
+offsets = {}
+def descend(offset, prefix, node):
+    (name, members) = node
+    offsets[prefix + name] = offset
+    start = offset
+    for m in members:
+        if isinstance(m, tuple):
+            (field, size) = m
+            # print prefix, name, field, offset
+            offsets["%s%s_%s" % (prefix, name, field)] = offset
+            offset += size
+        else:
+            for n in m:
+                descend(offset, prefix, n)
+    # print prefix, name, "SIZE", offset - start
+    offsets["%s%s_SIZE" % (prefix, name)] = offset - start
+
+descend(0, 'OFFSET_', layout[0])

+ 150 - 0
j1/firmware/defines_tcpip2.fs

@@ -0,0 +1,150 @@
+0 constant ETH
+14 constant ETH.ARP
+32 constant ETH.ARP.DST_ETH
+38 constant ETH.ARP.DST_IP
+20 constant ETH.ARP.OPCODE
+14 constant ETH.ARP.SOMETHING
+22 constant ETH.ARP.SRC_ETH
+28 constant ETH.ARP.SRC_IP
+0 constant ETH.DST
+14 constant ETH.IP
+24 constant ETH.IP.CHKSUM
+30 constant ETH.IP.DSTIP
+34 constant ETH.IP.ICMP
+36 constant ETH.IP.ICMP.CHKSUM
+38 constant ETH.IP.ICMP.IDENTIFIER
+40 constant ETH.IP.ICMP.SEQUENCE
+34 constant ETH.IP.ICMP.TYPECODE
+18 constant ETH.IP.IPID
+20 constant ETH.IP.IPOFFSET
+16 constant ETH.IP.LENGTH
+26 constant ETH.IP.SRCIP
+34 constant ETH.IP.TCP
+42 constant ETH.IP.TCP.ACK
+50 constant ETH.IP.TCP.CHECKSUM
+36 constant ETH.IP.TCP.DESTPORT
+46 constant ETH.IP.TCP.FLAGS
+38 constant ETH.IP.TCP.SEQNUM
+34 constant ETH.IP.TCP.SOURCEPORT
+52 constant ETH.IP.TCP.URGENT
+48 constant ETH.IP.TCP.WINDOW
+22 constant ETH.IP.TTLPROTO
+34 constant ETH.IP.UDP
+40 constant ETH.IP.UDP.CHECKSUM
+36 constant ETH.IP.UDP.DESTPORT
+42 constant ETH.IP.UDP.DHCP
+70 constant ETH.IP.UDP.DHCP.CHADDR
+54 constant ETH.IP.UDP.DHCP.CIADDR
+150 constant ETH.IP.UDP.DHCP.FILE
+52 constant ETH.IP.UDP.DHCP.FLAGS
+66 constant ETH.IP.UDP.DHCP.GIADDR
+44 constant ETH.IP.UDP.DHCP.HLEN
+45 constant ETH.IP.UDP.DHCP.HOPS
+43 constant ETH.IP.UDP.DHCP.HTYPE
+42 constant ETH.IP.UDP.DHCP.OP
+278 constant ETH.IP.UDP.DHCP.OPTIONS
+50 constant ETH.IP.UDP.DHCP.SECS
+62 constant ETH.IP.UDP.DHCP.SIADDR
+86 constant ETH.IP.UDP.DHCP.SNAME
+46 constant ETH.IP.UDP.DHCP.XID
+58 constant ETH.IP.UDP.DHCP.YIADDR
+42 constant ETH.IP.UDP.DNS
+44 constant ETH.IP.UDP.DNS.FLAGS
+42 constant ETH.IP.UDP.DNS.IDENTIFICATION
+48 constant ETH.IP.UDP.DNS.NOA
+52 constant ETH.IP.UDP.DNS.NOARR
+46 constant ETH.IP.UDP.DNS.NOQ
+50 constant ETH.IP.UDP.DNS.NORR
+54 constant ETH.IP.UDP.DNS.QUERY
+38 constant ETH.IP.UDP.LENGTH
+42 constant ETH.IP.UDP.LOADER
+46 constant ETH.IP.UDP.LOADER.FLASHREAD
+46 constant ETH.IP.UDP.LOADER.FLASHREAD.ADDR
+46 constant ETH.IP.UDP.LOADER.FLASHWRITE
+46 constant ETH.IP.UDP.LOADER.FLASHWRITE.ADDR
+50 constant ETH.IP.UDP.LOADER.FLASHWRITE.DATA
+44 constant ETH.IP.UDP.LOADER.OPCODE
+46 constant ETH.IP.UDP.LOADER.RAMREAD
+46 constant ETH.IP.UDP.LOADER.RAMREAD.ADDR
+46 constant ETH.IP.UDP.LOADER.RAMWRITE
+46 constant ETH.IP.UDP.LOADER.RAMWRITE.ADDR
+48 constant ETH.IP.UDP.LOADER.RAMWRITE.DATA
+42 constant ETH.IP.UDP.LOADER.SEQNO
+42 constant ETH.IP.UDP.NTP
+42 constant ETH.IP.UDP.NTP.FLAGS
+66 constant ETH.IP.UDP.NTP.ORIGINATE
+74 constant ETH.IP.UDP.NTP.RECEIVE
+58 constant ETH.IP.UDP.NTP.REFERENCE
+54 constant ETH.IP.UDP.NTP.REFID
+46 constant ETH.IP.UDP.NTP.ROOTDELAY
+50 constant ETH.IP.UDP.NTP.ROOTDISPERSION
+82 constant ETH.IP.UDP.NTP.TRANSMIT
+34 constant ETH.IP.UDP.SOURCEPORT
+42 constant ETH.IP.UDP.TFTP
+44 constant ETH.IP.UDP.TFTP.ACK
+44 constant ETH.IP.UDP.TFTP.ACK.BLOCK
+44 constant ETH.IP.UDP.TFTP.DATA
+44 constant ETH.IP.UDP.TFTP.DATA.BLOCK
+46 constant ETH.IP.UDP.TFTP.DATA.DATA
+44 constant ETH.IP.UDP.TFTP.ERROR
+46 constant ETH.IP.UDP.TFTP.ERROR.MESSAGE
+44 constant ETH.IP.UDP.TFTP.ERROR.NUMBER
+42 constant ETH.IP.UDP.TFTP.OPCODE
+44 constant ETH.IP.UDP.TFTP.RWRQ
+44 constant ETH.IP.UDP.TFTP.RWRQ.FILENAME
+42 constant ETH.IP.UDP.WGE
+82 constant ETH.IP.UDP.WGE.CONFIGURE
+90 constant ETH.IP.UDP.WGE.CONFIGURE.IP
+82 constant ETH.IP.UDP.WGE.CONFIGURE.PRODUCT
+86 constant ETH.IP.UDP.WGE.CONFIGURE.SERIAL
+82 constant ETH.IP.UDP.WGE.DISCOVER
+82 constant ETH.IP.UDP.WGE.DISCOVER.IP
+82 constant ETH.IP.UDP.WGE.FLASHREAD
+82 constant ETH.IP.UDP.WGE.FLASHREAD.ADDRESS
+82 constant ETH.IP.UDP.WGE.FLASHWRITE
+82 constant ETH.IP.UDP.WGE.FLASHWRITE.ADDRESS
+86 constant ETH.IP.UDP.WGE.FLASHWRITE.DATA
+50 constant ETH.IP.UDP.WGE.HRT
+82 constant ETH.IP.UDP.WGE.IMAGERMODE
+82 constant ETH.IP.UDP.WGE.IMAGERMODE.MODE
+82 constant ETH.IP.UDP.WGE.IMAGERSETRES
+82 constant ETH.IP.UDP.WGE.IMAGERSETRES.HORIZONTAL
+84 constant ETH.IP.UDP.WGE.IMAGERSETRES.VERTICAL
+42 constant ETH.IP.UDP.WGE.MAGIC
+80 constant ETH.IP.UDP.WGE.PAD
+66 constant ETH.IP.UDP.WGE.REPLYTO
+74 constant ETH.IP.UDP.WGE.REPLYTO.IP
+66 constant ETH.IP.UDP.WGE.REPLYTO.MAC
+78 constant ETH.IP.UDP.WGE.REPLYTO.PORT
+82 constant ETH.IP.UDP.WGE.SENSORREAD
+82 constant ETH.IP.UDP.WGE.SENSORREAD.ADDRESS
+82 constant ETH.IP.UDP.WGE.SENSORSELECT
+83 constant ETH.IP.UDP.WGE.SENSORSELECT.ADDRESS
+82 constant ETH.IP.UDP.WGE.SENSORSELECT.INDEX
+82 constant ETH.IP.UDP.WGE.SENSORWRITE
+82 constant ETH.IP.UDP.WGE.SENSORWRITE.ADDRESS
+83 constant ETH.IP.UDP.WGE.SENSORWRITE.DATA
+82 constant ETH.IP.UDP.WGE.SYSCONFIG
+82 constant ETH.IP.UDP.WGE.SYSCONFIG.MAC
+88 constant ETH.IP.UDP.WGE.SYSCONFIG.SERIAL
+82 constant ETH.IP.UDP.WGE.TRIGCONTROL
+82 constant ETH.IP.UDP.WGE.TRIGCONTROL.TRIGSTATE
+46 constant ETH.IP.UDP.WGE.TYPE
+82 constant ETH.IP.UDP.WGE.VIDSTART
+90 constant ETH.IP.UDP.WGE.VIDSTART.IP
+82 constant ETH.IP.UDP.WGE.VIDSTART.MAC
+94 constant ETH.IP.UDP.WGE.VIDSTART.PORT
+14 constant ETH.IP.VHLTOS
+6 constant ETH.SRC
+12 constant ETH.TYPE
+1 constant IP_PROTO_ICMP
+2 constant IP_PROTO_IGMP
+6 constant IP_PROTO_TCP
+17 constant IP_PROTO_UDP
+2 constant NUM_TCPS
+16 constant TCP_ACK
+1 constant TCP_FIN
+8 constant TCP_PSH
+4 constant TCP_RST
+2 constant TCP_SYN
+32 constant TCP_URG

+ 215 - 0
j1/firmware/defines_tcpip2.py

@@ -0,0 +1,215 @@
+layout = [
+    ('ETH', [
+        ('DST', 6),
+        ('SRC',  6),
+        ('TYPE', 2),
+        [
+            ('ARP', [
+                ('SOMETHING', 6),
+                ('OPCODE', 2),
+                ('SRC_ETH', 6),
+                ('SRC_IP', 4),
+                ('DST_ETH', 6),
+                ('DST_IP', 4) ]),
+            ('IP', [
+                ('VHLTOS', 2),
+                ('LENGTH', 2),
+                ('IPID', 2),
+                ('IPOFFSET', 2),
+                ('TTLPROTO', 2),
+                ('CHKSUM', 2),
+                ('SRCIP', 4),
+                ('DSTIP', 4),
+                [
+                    ('ICMP', [
+                        ('TYPECODE', 2),
+                        ('CHKSUM', 2),
+                        ('IDENTIFIER', 2),
+                        ('SEQUENCE', 2) ]),
+                    ('TCP', [
+                        ('SOURCEPORT', 2),
+                        ('DESTPORT', 2),
+                        ('SEQNUM', 4),
+                        ('ACK', 4),
+                        ('FLAGS', 2),
+                        ('WINDOW', 2),
+                        ('CHECKSUM', 2),
+                        ('URGENT', 2) ]),
+                    ('UDP', [
+                        ('SOURCEPORT', 2),
+                        ('DESTPORT', 2),
+                        ('LENGTH', 2),
+                        ('CHECKSUM', 2),
+                        [
+                            ('DHCP', [
+                                ('OP', 1),
+                                ('HTYPE', 1),
+                                ('HLEN', 1),
+                                ('HOPS', 1),
+                                ('XID', 4),
+                                ('SECS', 2),
+                                ('FLAGS', 2),
+                                ('CIADDR', 4),
+                                ('YIADDR', 4),
+                                ('SIADDR', 4),
+                                ('GIADDR', 4),
+                                ('CHADDR', 16),
+                                ('SNAME', 64),
+                                ('FILE', 128),
+                                ('OPTIONS', 312)
+                            ]),
+                            ('DNS', [
+                                ('IDENTIFICATION', 2),
+                                ('FLAGS', 2),
+                                ('NOQ', 2),
+                                ('NOA', 2),
+                                ('NORR', 2),
+                                ('NOARR', 2),
+                                ('QUERY', 1)
+                            ]),
+                            ('NTP', [
+                                ('FLAGS', 4),
+                                ('ROOTDELAY', 4),
+                                ('ROOTDISPERSION', 4),
+                                ('REFID', 4),
+                                ('REFERENCE', 8),
+                                ('ORIGINATE', 8),
+                                ('RECEIVE', 8),
+                                ('TRANSMIT', 8),
+                            ]),
+                            ('TFTP', [
+                                ('OPCODE', 2),
+                                [
+                                    ('RWRQ', [
+                                        ('FILENAME', 512)
+                                    ]),
+                                    ('DATA', [
+                                        ('BLOCK', 2),
+                                        ('DATA', 512)
+                                    ]),
+                                    ('ACK', [
+                                        ('BLOCK', 2),
+                                    ]),
+                                    ('ERROR', [
+                                        ('NUMBER', 2),
+                                        ('MESSAGE', 512),
+                                    ]),
+                                ]
+                            ]),
+                            ('LOADER', [
+                                ('SEQNO', 2),
+                                ('OPCODE', 2),
+                                [
+                                    ('RAMREAD', [
+                                        ('ADDR', 2)
+                                    ]),
+                                    ('RAMWRITE', [
+                                        ('ADDR', 2),
+                                        ('DATA', 128)
+                                    ]),
+                                    ('FLASHREAD', [
+                                        ('ADDR', 4)
+                                    ]),
+                                    ('FLASHWRITE', [
+                                        ('ADDR', 4),
+                                        ('DATA', 128)
+                                    ]),
+                                ]
+                            ]),
+                            ('WGE', [
+                                ('MAGIC', 4),
+                                ('TYPE', 4),
+                                ('HRT', 16),
+                                ('REPLYTO', [
+                                    ('MAC', 8),
+                                    ('IP', 4),
+                                    ('PORT', 2),
+                                ]),
+                                ('PAD', 2),
+                                [
+                                    ('DISCOVER', [
+                                        ('IP', 4)
+                                    ]),
+                                    ('CONFIGURE', [
+                                        ('PRODUCT', 4),
+                                        ('SERIAL', 4),
+                                        ('IP', 4)
+                                    ]),
+                                    ('FLASHREAD', [
+                                        ('ADDRESS', 4)
+                                    ]),
+                                    ('FLASHWRITE', [
+                                        ('ADDRESS', 4),
+                                        ('DATA', 264),
+                                    ]),
+                                    ('TRIGCONTROL', [
+                                        ('TRIGSTATE', 4),
+                                    ]),
+                                    ('SENSORREAD', [
+                                        ('ADDRESS', 1),
+                                    ]),
+                                    ('SENSORWRITE', [
+                                        ('ADDRESS', 1),
+                                        ('DATA', 2),
+                                    ]),
+                                    ('SENSORSELECT', [
+                                        ('INDEX', 1),
+                                        ('ADDRESS', 4),
+                                    ]),
+                                    ('IMAGERMODE', [
+                                        ('MODE', 4),
+                                    ]),
+                                    ('IMAGERSETRES', [
+                                        ('HORIZONTAL', 2),
+                                        ('VERTICAL', 2),
+                                    ]),
+                                    ('SYSCONFIG', [
+                                        ('MAC', 6),
+                                        ('SERIAL', 4),
+                                    ]),
+                                    ('VIDSTART', [
+                                        ('MAC', 8),
+                                        ('IP', 4),
+                                        ('PORT', 2),
+                                    ]),
+                                ]
+                            ]),
+                        ]
+                    ])
+                ]
+            ])
+        ]])
+]
+
+offsets = {}
+def descend(offset, prefix, node):
+    start = offset
+    if isinstance(node, list):
+        for n in node:
+            descend(offset, prefix, n)
+    else:
+        (name, members) = node
+        offsets[".".join((prefix + [name]))] = offset
+        if isinstance(members, int):
+            offset += members
+        else:
+            for n in members:
+                offset = descend(offset, prefix + [name], n)
+            # offsets["%s%s_SIZE" % (prefix, name)] = offset - start
+    return offset
+
+descend(0, [], layout[0])
+
+offsets['TCP_FIN'] = 1
+offsets['TCP_SYN'] = 2
+offsets['TCP_RST'] = 4
+offsets['TCP_PSH'] = 8
+offsets['TCP_ACK'] = 16
+offsets['TCP_URG'] = 32
+
+offsets['IP_PROTO_ICMP'] = 1
+offsets['IP_PROTO_IGMP'] = 2
+offsets['IP_PROTO_TCP'] = 6
+offsets['IP_PROTO_UDP'] = 17
+
+offsets['NUM_TCPS'] = 2

+ 176 - 0
j1/firmware/dhcp.fs

@@ -0,0 +1,176 @@
+( DHCP: Dynamic Host Configuration Protocol  JCB 13:13 08/24/10)
+module[ dhcp"
+
+\  Since DHCP alarm is only used when there is no lease, it is
+\  safe to use the ip-subnetmask for the same purpose.
+
+ip-subnetmask constant dhcp-alarm
+
+: dhcp-xid
+    ip-router 2@
+;
+
+: dhcp-xid!
+    ip-router 2!
+;
+
+: dhcp-option  \  ( ... n code -- )
+    mac-pkt-c,
+    dup mac-pkt-c,
+    0do
+        mac-pkt-c,
+    loop
+;
+
+: dhcp-common   \  ( messagetype -- )
+    d# 67 d# 68
+    d# 0 invert dup
+    d# 0 dup
+    d# 0               \  broadcast ethaddr
+                            ( dst-port src-port dst-ip src-ip *ethaddr -- )
+    udp-header
+    h# 0101 h# 0600 mac-pkt-2,
+    dhcp-xid mac-pkt-2,
+    d# 10 mac-pkt-,0
+    net-my-mac mac-pkt-3,
+    d# 101 mac-pkt-,0          \  d# 5 + d# 96 zeroes
+
+    h# 6382 h# 5363
+    mac-pkt-2,
+
+    \  DHCP option 53: DHCP Discover
+                            \  messagetype
+    d# 1 d# 53                    \  messagetype 1 53
+    dhcp-option
+
+    \  DHCP option 50: 192.168.1.100 requested
+
+    \  DHCP option 55: Parameter Request List: 
+    \  Request Subnet Mask (1), Router (3),
+    \  Domain Name Server (6)
+    d# 1 d# 3 d# 6   d# 3 d# 55 dhcp-option
+;
+
+: dhcp-wrapup
+    \  Finish options
+    h# ff mac-pkt-c,
+    \ mac-wrptr @ d# 1 and 
+    d# 1 if    \ XXX
+        h# ff mac-pkt-c,
+    then
+
+    udp-wrapup
+    mac-send
+;
+
+\  memory layout is little-endian
+
+: macc@++ ( c-addr -- c-addr+1 c )
+    dup 1+ swap macc@ ;
+
+: dhcp-field    \  ( match -- ptr/0 )
+    OFFSET_DHCP_OPTIONS d# 4 + mac-inoffset 
+                            \  match ptr
+    begin
+        macc@++             \  match ptr code
+        dup h# ff <>
+    while                   \  match ptr code
+        d# 2 pick =                  
+        if
+            nip             \  ptr
+            exit
+        then                \  match ptr
+        macc@++ +           \  match ptr'
+    repeat
+    \  fail - return false
+    2drop false
+;
+
+: dhcp-yiaddr
+    d# 2 OFFSET_DHCP_YIADDR mac-inoffset mac@n
+;
+
+: dhcp-field4
+    dhcp-field d# 1 +
+    macc@++ swap macc@++ swap macc@++ swap macc@
+                            ( a b c d )
+    swap d# 8 lshift or -rot
+    swap d# 8 lshift or
+    swap
+;
+
+build-debug? [IF]
+: .pad ( ip. c-addr u -- )  d# 14 typepad ip-pretty cr ;
+
+: dhcp-status
+    ip-addr 2@ s" IP" .pad
+    ip-router 2@ s" router" .pad
+    ip-subnetmask 2@ s" subnetmask" .pad
+;
+[ELSE]
+: dhcp-status ;
+[THEN]
+
+: lease-setalarm
+    d# 0 >r
+    begin
+        2dup d# 63. d>
+    while
+        d2/ r> 1+ >r
+    repeat
+    r>
+    hex4 space hex8 cr
+;
+
+: dhcp-wait-offer
+    h# 11 ip-isproto
+    OFFSET_UDP_SOURCEPORT packet@ d# 67 = and
+    OFFSET_UDP_DESTPORT packet@ d# 68 = and
+    d# 2 OFFSET_DHCP_XID mac-inoffset mac@n dhcp-xid d= and
+    if
+        snap
+        d# 53 dhcp-field ?dup
+        snap
+        if 
+            d# 1 + macc@ 
+            snap
+            dup d# 2 =
+            if
+                \ [char] % emit
+                d# 3 dhcp-common
+
+                \  option 50: request IP
+                h# 3204
+                dhcp-yiaddr
+                mac-pkt-3,
+
+                \  Option 54: server
+                h# 3604
+                d# 54 dhcp-field4
+                mac-pkt-3,
+
+                dhcp-wrapup
+            then
+            d# 5 =
+            if
+                \ clrwdt
+                \ [char] & emit
+
+                dhcp-yiaddr ip-addr 2!
+                d# 1 dhcp-field4 ip-subnetmask 2!
+                \  For the router and DNS server, send out ARP requests right now.  This
+                \  reduces start-up time.
+                d# 3 dhcp-field4 2dup ip-router 2! arp-lookup drop 
+                d# 6 dhcp-field4 2dup ip-dns    2! arp-lookup drop 
+                \  Option 51: lease time
+                s" expires in " type
+                d# 51 dhcp-field4 swap d. cr
+            then
+        then
+        snap
+    then
+;
+
+: dhcp-discover d# 1 dhcp-common dhcp-wrapup ;
+
+]module

+ 81 - 0
j1/firmware/dns.fs

@@ -0,0 +1,81 @@
+( DNS                                        JCB 19:44 11/27/10)
+module[ dns"
+
+: ip-dns@ ip-dns 2@ ;
+
+\ ( offset -- offset' ) advance pointer past DNS label
+\ 0     means end
+\ >h# c0 means ptr to end
+\ N     means word of N bytes
+
+: dns-skiplabel
+    begin
+        dup 1+ swap mac-inoffset macc@        \  offset+1 v
+        dup 0= if
+            drop exit
+        then
+        dup h# c0 >= if
+            drop 1+ exit
+        then
+        +
+    again
+;
+
+\ Query DNS. xt is a word that appends domainname to packet.  id is DNS
+\ id field, used to route responses.
+
+: dns-query ( xt id -- )
+    >r
+    \ dst-port src-port dst-ip src-ip *ethaddr
+    d# 53 d# 31947 
+    ip-dns@
+    net-my-ip
+    ip-dns@ arp-lookup
+    udp-header
+    r>          \ IDENTIFICATION
+    h# 0100     \ FLAGS
+    d# 1        \ NOQ
+    mac-pkt-3,
+    d# 3 mac-pkt-,0
+    
+    execute
+
+    d# 1        \ query type A
+    dup         \ query class internet
+    mac-pkt-2,
+    udp-wrapup
+
+    ip-dns@ arp-lookup if
+        mac-send
+    then
+;
+
+: dns-handler ( srcport dstport  -- 0 / ip. id 1 )
+    d# 53 d# 31947 d=
+    OFFSET_DNS_FLAGS packet@ 0< and
+    OFFSET_DNS_NOA packet@ 0<> and
+    if
+        OFFSET_DNS_QUERY
+        dns-skiplabel
+        d# 4 +
+        dns-skiplabel
+        d# 10 +
+        mac-inoffset d# 2 swap mac@n
+        OFFSET_DNS_IDENTIFICATION packet@
+        d# 1
+    else
+        d# 0
+    then
+;
+
+: dns-appendname        ( str -- )
+    dup mac-pkt-c,
+    mac-pkt-s,
+;
+
+: dns-append.com        ( str -- )
+    dns-appendname
+    s" com" dns-appendname
+    d# 0 mac-pkt-c,
+;
+]module

+ 20 - 0
j1/firmware/doc.fs

@@ -0,0 +1,20 @@
+( Documentation conventions                  JCB 14:37 10/26/10)
+
+meta
+
+: getword ( -- a u )
+    begin
+        bl word count dup 0=
+    while
+        2drop refill true <> abort" Failed to find word"
+    repeat
+;
+
+: ================================================================
+    begin
+        getword
+        nip 64 =
+    until
+;
+
+target

+ 3 - 0
j1/firmware/document.fs

@@ -0,0 +1,3 @@
+\ For use with docforth.fs
+
+s" ans.fs" included

+ 28 - 0
j1/firmware/encode.py

@@ -0,0 +1,28 @@
+import sys
+import Image
+from array import array
+
+def getch(im, x, y):
+    return tuple(tuple((int(0 != im.getpixel((x + j, y + i)))) for j in range(8)) for i in range(8))
+    
+def main(filename):
+    sm = Image.open(filename).convert("L")
+    im = Image.new("L", (512, 256))
+    im.paste(sm, (0,0))
+    charset = {}
+    picture = []
+    for y in range(0, im.size[1], 8):
+        for x in range(0, im.size[0], 8):
+            glyph = getch(im, x, y)
+            if not glyph in charset:
+                charset[glyph] = 96 + len(charset)
+            picture.append(charset[glyph])
+    open(filename + ".pic", "w").write(array('B', picture).tostring())
+    cd = array('B', [0] * 8 * len(charset))
+    for d,i in charset.items():
+        i -= 96
+        for y in range(8):
+            cd[8 * i + y] = sum([(d[y][x] << (7 - x)) for x in range(8)])
+    open(filename + ".chr", "w").write(cd.tostring())
+
+main(sys.argv[1])

+ 506 - 0
j1/firmware/eth-ax88796.fs

@@ -0,0 +1,506 @@
+( Low-level MAC actions                      JCB 13:23 08/24/10)
+
+================================================================
+
+Initialization:
+    mac-cold
+
+Packet reception and reading:
+    mac-fullness
+    mac-inoffset
+    mac@
+    macc@
+    mac@n
+    mac-consume
+
+Packet construction and transmission:
+    mac-pkt-begin
+    mac-pkt-,
+    mac-pkt-c,
+    mac-pkt-d,
+    mac-pkt-2,
+    mac-pkt-3,
+    mac-pkt-,0
+    mac-pkt-s,
+    mac-pkt-src
+    packetout-off
+    mac!
+    macc!
+    mac-complete
+    mac-checksum
+    mac-send
+
+================================================================
+
+( NE2K                                       JCB 10:23 11/08/10)
+
+: ne2sel
+    false ether_cs_n ! ;
+: ne2unsel
+    true ether_cs_n ! ;
+: ne2a ( a -- )
+    pb_a ! ;
+
+: ne2rc@ ( a -- u ) \ NE2 byte reg read
+    true ether_bhe_n !
+    true ether_aen !
+    ne2sel
+    ne2a
+    false pb_rd_n !
+    \ pause144
+    pb_d @ h# ff and
+    true pb_rd_n !
+    \ false ether_aen ! 
+    \ ne2unsel
+;
+
+: ne2rc! ( u a -- )
+    \ over hex2 s"  -> " type dup hex2 cr
+
+    true ether_bhe_n !
+
+    ne2sel
+    ne2a
+    pb_d !
+    d# 0 ddir !
+    false pb_wr_n !
+    true pb_wr_n !
+    \ ne2unsel
+    d# 1 ddir !
+;
+
+: ne2r! ( u a -- )
+    over d# 8 rshift over 1+ ne2rc! ne2rc! ;
+
+: ne2r. \ dump registers
+    d# 16 0do
+        d# 1000 0do pause144 loop
+        i hex2 space
+        i ne2rc@ hex4 cr
+    loop
+;
+
+h# 00 constant ne2-CR       
+h# 01 constant ne2-PSTART   
+h# 01 constant ne2-PAR0     
+h# 03 constant ne2-PAR2     
+h# 05 constant ne2-PAR4     
+h# 01 constant ne2-CR9346   
+h# 02 constant ne2-PSTOP    
+h# 03 constant ne2-BNRY     
+h# 04 constant ne2-TSR      
+h# 04 constant ne2-TPSR     
+h# 05 constant ne2-TBCR0    
+h# 05 constant ne2-NCR      
+h# 06 constant ne2-CPR      
+h# 06 constant ne2-TBCR1    
+h# 07 constant ne2-ISR      
+h# 07 constant ne2-CURR     
+h# 08 constant ne2-RSAR0    
+h# 08 constant ne2-CRDA0    
+h# 09 constant ne2-RSAR1    
+h# 09 constant ne2-CRDA1    
+h# 0A constant ne2-RBCR0    
+h# 0B constant ne2-RBCR1    
+h# 0C constant ne2-RSR      
+h# 0C constant ne2-RCR      
+h# 0D constant ne2-TCR      
+h# 0D constant ne2-CNTR0    
+h# 0E constant ne2-DCR      
+h# 0E constant ne2-CNTR1    
+h# 0F constant ne2-IMR      
+h# 0F constant ne2-CNTR2    
+h# 10 constant ne2-RDMAPORT 
+h# 14 constant ne2-MIIEEP
+h# 15 constant ne2-TR  
+h# 17 constant ne2-GPOC  
+h# 17 constant ne2-GPI
+h# 1F constant ne2-RSTPORT  
+
+: ne2-page0 h# 22 ne2-CR ne2rc!  ;
+: ne2-page1 h# 62 ne2-CR ne2rc!  ;
+
+: ne2-clrisr \ clear the ISR
+    h# ff ne2-ISR    ne2rc! ; 
+
+
+: ne2r.2
+    s" Page 0" type cr
+    ne2-page0
+    ne2r.
+    s" Page 1" type cr
+    ne2-page1
+    ne2r.
+    ne2-page0 ;
+
+( The MII interface                          JCB 12:47 11/09/10)
+
+h# 08 constant MII_EEP_MDO
+h# 04 constant MII_EEP_MDI
+h# 01 constant MII_EEP_MDC
+
+: eep-on  ( u ) ne2-MIIEEP ne2rc@ or ne2-MIIEEP ne2rc! ;
+: eep-off ( u ) invert ne2-MIIEEP ne2rc@ and ne2-MIIEEP ne2rc! ;
+
+: miix ( u c -- u ) \ Send c bit data u
+    tuck
+    d# 16 swap - lshift
+    swap
+    0do
+        MII_EEP_MDO over 0< if
+            eep-on
+        else
+            eep-off
+        then
+        MII_EEP_MDC eep-on \ clock up
+        2*
+        ne2-MIIEEP ne2rc@ MII_EEP_MDI and if 1+ then
+        MII_EEP_MDC eep-off \ clock down
+    loop
+;
+
+: phy@ ( a -- u )
+    h# ffff d# 16 miix drop
+    h# ffff d# 16 miix drop
+    h# 0d0 d# 9 miix drop
+          d# 5 miix drop
+    h# 0 d# 1 miix drop
+    h# 0 d# 16 miix
+;
+
+: phy! ( u a -- )
+    h# ffff d# 16 miix drop
+    h# ffff d# 16 miix drop
+    h# 0b0 d# 9 miix drop
+          d# 5 miix drop
+    h# 2 d# 2 miix drop
+         d# 16 miix drop
+;
+
+: phy.
+    d# 32 0do
+        i hex2 space i phy@ hex4 cr
+    loop
+    cr
+;
+
+: phy-cold
+    \ h# b000 d# 0 phy! 
+    h# 0800 d# 0 phy!
+    s" PHY power down for 2.5s" type cr
+    d# 2500000. sleepus
+    \ h# 1200 d# 0 phy!
+    h# 0000 d# 0 phy!
+    exit
+    sleep1 
+    sleep1 
+    sleep1 
+    sleep1 
+    sleep1 
+    sleep1 
+
+    \ h# 6030 d# 30 phy!
+
+    phy. sleep1
+    cr
+    phy. 
+;
+
+: mac-cold   ( ethaddr -- )
+
+    false RESET_TRIGGER !
+    sleep1
+    true RESET_TRIGGER !
+    sleep1
+
+    true pb_rd_n !
+    true pb_wr_n !
+    true ether_cs_n !
+    false ether_aen !
+    true ether_bhe_n !
+    d# 0 pb_a !
+    d# 1 ddir !
+
+    \ d# 4 0do ne2-RSTPORT ne2rc@ ne2-RSTPORT ne2rc!  sleep1 loop
+
+    phy-cold
+
+    \ Wait for TR RST_B to go low and GPI link up
+    s" TR   GPI" type cr
+    begin
+        ne2-TR ne2rc@ hex2 d# 3 spaces
+        ne2-GPI ne2rc@ hex2 d# 3 spaces
+        sleep.1
+        cr
+        ne2-TR ne2rc@ d# 2 and 0=
+        ne2-GPI ne2rc@ d# 1 and 0<> and
+    until
+
+    \ Wait for TR RST_B to go low
+\   begin
+\       sleep1
+\       ne2-TR ne2rc@ dup hex2 cr
+\       d# 2 and 0=
+\   until
+
+    true if
+        h# 21 ne2-CR     ne2rc! \ Stop the NIC, abort DMA, page 0
+        h# 00 ne2-DCR    ne2rc! \ Selects byte-wide DMA transfers
+        h# 00 ne2-RBCR0  ne2rc! \ Load data byte count for remote DMA
+        h# 00 ne2-RBCR1  ne2rc!
+        h# 20 ne2-RCR    ne2rc! \ Temporarily set receiver to monitor mode
+        h# 02 ne2-TCR    ne2rc! \ Transmitter set to internal loopback mode
+        \ Initialize Receive Buffer Ring: Boundary Pointer
+        \ (BNDRY), Page Start (PSTART), and Page Stop
+        \ (PSTOP)
+        h# 46 ne2-PSTART ne2rc!
+        h# 46 ne2-BNRY   ne2rc!
+        h# 80 ne2-PSTOP  ne2rc!
+        h# ff ne2-ISR    ne2rc! \ Clear Interrupt Status Register (ISR) by writing 0FFh to it.
+        h# 01 ne2-IMR    ne2rc! \ Initialize interrupt mask
+        h# 61 ne2-CR     ne2rc! \ Stop the NIC, abort DMA, page 1
+        h# 12 d# 1       ne2rc! \ Set Physical Address
+        h# 34 d# 2       ne2rc!
+        h# 56 d# 3       ne2rc!
+        h# 77 d# 4       ne2rc!
+        h# 77 d# 5       ne2rc!
+        h# 77 d# 6       ne2rc!
+        d# 16 d# 8 do           \ Set multicast address
+            h# 00 i ne2rc!
+        loop
+
+        h# 47 ne2-CURR   ne2rc! \ Initialize CURRent pointer
+        h# 22 ne2-CR     ne2rc! \ Start the NIC, Abort DMA, page 0
+        h# 10 ne2-GPOC   ne2rc! \ Select media interface
+        s" GPI = " type ne2-GPI ne2rc@ hex2 cr
+        h# 00 ne2-TCR    ne2rc! \ Transmitter full duplex
+        h# 04 ne2-RCR    ne2rc! \ Enable receiver and set accept broadcast
+    else
+        h# 21 ne2-CR     ne2rc! \ Stop the NIC, abort DMA, page 0
+        sleep.1
+
+        h# 00 ne2-DCR    ne2rc! \ Selects word-wide DMA transfers
+        h# 00 ne2-RBCR0  ne2rc! \ Load data byte count for remote DMA
+        h# 00 ne2-RBCR1  ne2rc!
+
+        h# 20 ne2-RCR    ne2rc! \ Temporarily set receiver to monitor mode
+        h# 02 ne2-TCR    ne2rc! \ Transmitter set to internal loopback mode
+
+        h# 40 ne2-TPSR   ne2rc! \ Set Tx start page
+        \ Initialize Receive Buffer Ring: Boundary Pointer
+        \ (BNDRY), Page Start (PSTART), and Page Stop
+        \ (PSTOP)
+        h# 46 ne2-PSTART ne2rc!
+        h# 46 ne2-BNRY   ne2rc!
+        h# 80 ne2-PSTOP  ne2rc!
+        h# ff ne2-ISR    ne2rc! \ Clear Interrupt Status Register (ISR) by writing 0FFh to it.
+        h# 01 ne2-IMR    ne2rc! \ Initialize interrupt mask
+
+        h# 61 ne2-CR     ne2rc! \ Stop the NIC, abort DMA, page 1
+        sleep.1
+        h# 12 d# 1       ne2rc! \ Set Physical Address
+        h# 34 d# 2       ne2rc!
+        h# 56 d# 3       ne2rc!
+        h# 77 d# 4       ne2rc!
+        h# 77 d# 5       ne2rc!
+        h# 77 d# 6       ne2rc!
+        d# 16 d# 8 do           \ Set multicast address
+            h# ff i ne2rc!
+        loop
+
+        h# 47 ne2-CURR   ne2rc! \ Initialize CURRent pointer
+
+        h# 20 ne2-CR     ne2rc! \ DMA abort, page 0
+
+        h# 10 ne2-GPOC   ne2rc! \ Select media interface
+        s" GPI = " type ne2-GPI ne2rc@ hex2 cr
+        h# 1c ne2-RCR    ne2rc! \ Enable receiver and set accept broadcast
+        h# 00 ne2-TCR    ne2rc! \ Transmitter full duplex
+
+        h# ff ne2-ISR    ne2rc! \ Clear Interrupt Status Register (ISR) by writing 0FFh to it.
+        h# 22 ne2-CR     ne2rc! \ Start the NIC, Abort DMA, page 0
+    then
+;
+
+: NicCompleteDma
+    h# 22 ne2-CR     ne2rc! \ Complete remote DMA
+;
+
+: maca ( a -- ) \ set DMA address a
+    dup d# 8 rshift ne2-RSAR1 ne2rc!  ne2-RSAR0 ne2rc! ;
+: mac1b \ set DMA transfer for 1 byte
+    h# 01 ne2-RBCR0 ne2rc!
+    h# 00 ne2-RBCR1 ne2rc! ;
+: mac2b \ set DMA transfer for 2 bytes
+    h# 02 ne2-RBCR0 ne2rc!
+    h# 00 ne2-RBCR1 ne2rc! ;
+: macc@ ( a -- u )
+    maca mac1b
+    h# 0a ne2-CR     ne2rc! \ running, DMA read
+    ne2-RDMAPORT ne2rc@
+    NicCompleteDma ;
+: macc! ( u a -- )
+    maca mac1b
+    h# 12 ne2-CR    ne2rc! \ running, DMA write
+    ne2-RDMAPORT ne2rc! ;
+: mac@ ( a -- u )
+    maca mac2b
+    h# 0a ne2-CR     ne2rc! \ running, DMA read
+    ne2-RDMAPORT ne2rc@ d# 8 lshift ne2-RDMAPORT ne2rc@ or
+    NicCompleteDma ;
+: mac! ( u a -- )
+    maca mac2b
+    h# 12 ne2-CR    ne2rc! \ running, DMA write
+    dup d# 8 rshift ne2-RDMAPORT ne2rc! ne2-RDMAPORT ne2rc! ;
+
+: mac-dump ( a u -- )
+    bounds
+    begin
+        2dup u>
+    while
+        dup h# f and 0= if
+            cr dup hex4 [char] : emit space
+        then
+        dup mac@ hex4 space
+        2+
+    repeat 2drop cr ;
+
+variable currpkt
+
+: mac-inoffset ( u -- u ) \ compute offset into current incoming packet
+    currpkt @ +
+    dup 0< if
+        h# 8000 -
+        h# 4600 +
+    then
+;
+
+: mac@n ( n addr -- d0 .. dn )
+    swap 0do dup mac@ swap 2+ loop drop ; 
+
+
+( words for constructing packet data         JCB 07:01 08/20/10)
+variable writer
+
+: mac-pkt-begin h# 4000 writer !  ;
+: bump  ( n -- ) writer +! ;
+: mac-pkt-c,    ( n -- ) writer @ macc! d# 1 bump ;
+: mac-pkt-,     ( n -- ) writer @ mac! d# 2 bump ;
+: mac-pkt-d,    ( d -- ) mac-pkt-, mac-pkt-, ;
+: mac-pkt-2,    ( n0 n1 -- ) swap mac-pkt-, mac-pkt-, ;
+: mac-pkt-3,    rot mac-pkt-, mac-pkt-2, ;
+: mac-pkt-,0    ( n -- ) 0do d# 0 mac-pkt-, loop ;
+: mac-pkt-s,    ( caddr u -- )
+    0do
+        dup c@
+        mac-pkt-c,
+        1+
+    loop
+    drop
+;
+
+: mac-pkt-src ( n offset -- ) \ copy n words from incoming+offset
+    swap 0do
+        dup mac-inoffset mac@ mac-pkt-,
+        2+
+    loop
+    drop
+;
+
+: mac-pkt-complete ( -- length ) \ set up size
+    writer @ h# 4000 -
+    \ h# 4000 over mac-dump
+    dup ne2-TBCR0 ne2r!  ;
+
+: mac-checksum ( addr nwords -- sum )
+    d# 0 swap
+    0do
+        over mac@       ( addr sum v )
+        +1c
+        swap 2+ swap
+    loop
+    nip
+    invert
+;
+
+: mac-snap
+    s" CR     PSTART PSTOP  BNRY   TSR    NCR    CPR    ISR    CRDA0  CRDA1  -      -      RSR    CNTR0  CNTR1  CNTR2" type cr
+    d# 16 0do
+        i ne2rc@ hex2 d# 5 spaces
+    loop
+;
+
+: mac-fullness ( -- f )
+    ether_irq @ if
+        ne2-BNRY ne2rc@ 1+ ne2-CPR ne2rc@ <> dup if
+            \ mac-snap
+            ne2-BNRY ne2rc@ 1+ d# 8 lshift d# 4 + currpkt !
+            \ s" currpkt=" type currpkt @ hex4 space
+            \ currpkt @ d# 4 - macc@ hex2 
+            \ cr
+            \ currpkt @ d# 4 - d# 16 mac-dump
+        else
+            ne2-clrisr
+        then
+    else
+        false
+    then
+;
+
+: mac-consume ( -- ) \ finished with current packet, move on
+    ne2-BNRY ne2rc@ 1+ d# 8 lshift 1+ macc@ \ next pkt
+    1- ne2-BNRY ne2rc!
+;
+
+variable ne2cold
+
+: mac-send
+    ne2cold @ 0= if
+        h# 21 ne2-CR ne2rc!
+        h# 22 ne2-CR ne2rc!
+        true ne2cold !
+    then
+
+    h# 40 ne2-TPSR ne2rc!
+    h# 26 ne2-CR ne2rc! \ START
+    ;
+
+: packetout-off           \  compute offset in output packet
+    h# 4000 + ;
+
+: nicwork
+
+    \ ISA mode
+
+    \ begin
+        s" TR= " type h# 15 ne2rc@ hex2 space
+        s" ether_irq=" type ether_irq @ hex1 space
+        s" ISR=" type ne2-ISR ne2rc@ hex2 space
+        cr
+    \ again
+
+    false if
+        h# 0000 ne2-RSAR0 ne2r!
+        cr
+        d# 16 0do
+            ne2-RDMAPORT ne2rc@ hex2 space
+        loop
+        cr
+    then
+
+    s" CR     PSTART PSTOP  BNRY   TSR    NCR    CPR    ISR    CRDA0  CRDA1  -      -      RSR    CNTR0  CNTR1  CNTR2" type cr
+    begin
+        d# 16 0do
+            i ne2rc@ hex2 d# 5 spaces
+        loop
+        ether_irq @ hex1
+        cr 
+        sleep1
+        ne2-CPR ne2rc@ h# 47 <>
+    until
+
+    \ h# 4700 h# 100 mac-dump
+    \ cr
+    \ h# 0947 h# 4700 mac!
+    \ h# 4700 h# 100 mac-dump
+;

BIN
j1/firmware/font8x8


BIN
j1/firmware/fsm-32.png


+ 11 - 0
j1/firmware/genoffsets.py

@@ -0,0 +1,11 @@
+from defines_tcpip import offsets
+
+d = open("defines_tcpip.fs", "w")
+for nm,o in sorted(offsets.items()):
+  print >>d, "%d constant %s" % (o, nm)
+
+import defines_tcpip2
+
+d = open("defines_tcpip2.fs", "w")
+for nm,o in sorted(defines_tcpip2.offsets.items()):
+  print >>d, "%d constant %s" % (o, nm)

+ 16 - 0
j1/firmware/go

@@ -0,0 +1,16 @@
+# make doc
+# python encode.py j1.png
+# python mkblob.py ; exit
+make j1.bin || exit
+
+# for ADDR in 0 80000 100000 180000
+# do
+#   (. /opt/Xilinx/11.1/ISE/settings32.sh ; promgen -u $ADDR j1_program.bit -p mcs -w -o j1_program_$ADDR.mcs )
+# done
+# ./boot
+# ping -c 4 192.168.0.99 && python twist.py
+
+python twist.py
+
+(. /opt/Xilinx/11.1/ISE/settings32.sh ; data2mem -bm ../synth/j1_bd.bmm -bd j1.mem tag jram -bt ../synth/j1.bit -o b j1_program.bit )
+scp j1_program.bit leonard:.

+ 57 - 0
j1/firmware/hwdefs.fs

@@ -0,0 +1,57 @@
+h# 4100 constant flash_ddir
+h# 4102 constant flash_ce_n
+h# 4104 constant flash_oe_n
+h# 4106 constant flash_we_n
+h# 4108 constant flash_byte_n
+h# 410a constant flash_rdy
+h# 410c constant flash_rst_n
+h# 410e constant flash_a
+h# 4110 constant flash_a_hi
+h# 4112 constant flash_d
+
+h# 4200 constant ps2_clk
+h# 4202 constant ps2_dat
+h# 4204 constant ps2_clk_dir
+h# 4206 constant ps2_dat_dir
+h# 4208 constant kbfifocount
+h# 4210 constant kbfifo
+
+h# 4300 constant vga_scroll
+h# 4302 constant vga_spritea
+h# 4304 constant vga_spriteport
+h# 4306 constant vga_line
+h# 4308 constant vga_addsprites
+
+h# 4400 constant vga_spritex
+h# 4402 constant vga_spritey
+
+h# 4420 constant vga_spritec
+h# 4430 constant vga_spritep
+
+h# 4500 constant sw2_n
+h# 4502 constant sw3_n
+
+h# 5000 constant RS232_TXD
+h# 5001 constant RESET_TRIGGER
+h# 5100 constant ether_cs_n
+h# 5101 constant ether_aen
+h# 5102 constant ether_bhe_n
+h# 5103 constant pb_a
+h# 5104 constant ddir
+h# 5105 constant pb_d
+h# 5106 constant pb_rd_n
+h# 5107 constant pb_wr_n
+h# 5108 constant ether_rdy
+h# 5109 constant ether_irq
+h# 510a constant pb_a_dir
+
+h# 6000 constant time
+h# 6100 constant mult_a
+h# 6102 constant mult_b
+h# 6104 constant mult_p
+
+\ Pushbuttons
+
+h# 1 constant pb2
+h# 2 constant pb3
+h# 4 constant pb4

+ 643 - 0
j1/firmware/intelhex.py

@@ -0,0 +1,643 @@
+#!/usr/bin/python
+
+# Copyright (c) 2005-2007, Alexander Belchenko
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms,
+# with or without modification, are permitted provided
+# that the following conditions are met:
+#
+# * Redistributions of source code must retain
+#   the above copyright notice, this list of conditions
+#   and the following disclaimer.
+# * Redistributions in binary form must reproduce
+#   the above copyright notice, this list of conditions
+#   and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# * Neither the name of the <Alexander Belchenko>
+#   nor the names of its contributors may be used to endorse
+#   or promote products derived from this software
+#   without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'''Intel HEX file format reader and converter.
+
+This script also may be used as hex2bin convertor utility.
+
+@author     Alexander Belchenko (bialix AT ukr net)
+@version    0.8.6
+@date       2007/04/26
+'''
+
+
+__docformat__ = "javadoc"
+
+
+from array import array
+from binascii import hexlify, unhexlify
+
+
+class IntelHex:
+    ''' Intel HEX file reader. '''
+
+    def __init__(self, fname):
+        ''' Constructor.
+        @param  fname   file name of HEX file or file object.
+        '''
+        #public members
+        self.Error = None
+        self.AddrOverlap = None
+        self.padding = 0x0FF
+        # Start Address
+        self.start_addr = None
+
+        # private members
+        self._fname = fname
+        self._buf = {}
+        self._readed = False
+        self._eof = False
+        self._offset = 0
+
+    def readfile(self):
+        ''' Read file into internal buffer.
+        @return True    if successful.
+        '''
+        if self._readed:
+            return True
+
+        if not hasattr(self._fname, "read"):
+            f = file(self._fname, "rU")
+            fclose = f.close
+        else:
+            f = self._fname
+            fclose = None
+
+        self._offset = 0
+        self._eof = False
+
+        result = True
+
+        for s in f:
+            if not self.decode_record(s):
+                result = False
+                break
+
+            if self._eof:
+                break
+
+        if fclose:
+            fclose()
+
+        self._readed = result
+        return result
+
+    def decode_record(self, s):
+        ''' Decode one record of HEX file.
+        @param  s       line with HEX record.
+        @return True    if line decode OK, or this is not HEX line.
+                False   if this is invalid HEX line or checksum error.
+        '''
+        s = s.rstrip('\r\n')
+        if not s:
+            return True       # empty line
+
+        if s[0] == ':':
+            try:
+                bin = array('B', unhexlify(s[1:]))
+            except TypeError:
+                # this might be raised by unhexlify when odd hexascii digits
+                self.Error = "Odd hexascii digits"
+                return False
+            length = len(bin)
+            if length < 5:
+                self.Error = "Too short line"
+                return False
+        else:
+            return True     # first char must be ':'
+
+        record_length = bin[0]
+
+        if length != (5 + record_length):
+            self.Error = "Invalid line length"
+            return False
+
+        addr = bin[1]*256 + bin[2]
+
+        record_type = bin[3]
+        if not (0 <= record_type <= 5):
+            self.Error = "Invalid type of record: %d" % record_type
+            return False
+
+        crc = sum(bin)
+        crc &= 0x0FF
+        if crc != 0:
+            self.Error = "Invalid crc"
+            return False
+
+        if record_type == 0:
+            # data record
+            addr += self._offset
+            for i in xrange(4, 4+record_length):
+                if not self._buf.get(addr, None) is None:
+                    self.AddrOverlap = addr
+                self._buf[addr] = bin[i]
+                addr += 1       # FIXME: addr should be wrapped on 64K boundary
+
+        elif record_type == 1:
+            # end of file record
+            if record_length != 0:
+                self.Error = "Bad End-of-File Record"
+                return False
+            self._eof = True
+
+        elif record_type == 2:
+            # Extended 8086 Segment Record
+            if record_length != 2 or addr != 0:
+                self.Error = "Bad Extended 8086 Segment Record"
+                return False
+            self._offset = (bin[4]*256 + bin[5]) * 16
+
+        elif record_type == 4:
+            # Extended Linear Address Record
+            if record_length != 2 or addr != 0:
+                self.Error = "Bad Extended Linear Address Record"
+                return False
+            self._offset = (bin[4]*256 + bin[5]) * 65536
+
+        elif record_type == 3:
+            # Start Segment Address Record
+            if record_length != 4 or addr != 0:
+                self.Error = "Bad Start Segment Address Record"
+                return False
+            if self.start_addr:
+                self.Error = "Start Address Record appears twice"
+                return False
+            self.start_addr = {'CS': bin[4]*256 + bin[5],
+                               'IP': bin[6]*256 + bin[7],
+                              }
+
+        elif record_type == 5:
+            # Start Linear Address Record
+            if record_length != 4 or addr != 0:
+                self.Error = "Bad Start Linear Address Record"
+                return False
+            if self.start_addr:
+                self.Error = "Start Address Record appears twice"
+                return False
+            self.start_addr = {'EIP': (bin[4]*16777216 +
+                                       bin[5]*65536 +
+                                       bin[6]*256 +
+                                       bin[7]),
+                              }
+
+        return True
+
+    def _get_start_end(self, start=None, end=None):
+        """Return default values for start and end if they are None
+        """
+        if start is None:
+            start = min(self._buf.keys())
+        if end is None:
+            end = max(self._buf.keys())
+        if start > end:
+            start, end = end, start
+        return start, end
+
+    def tobinarray(self, start=None, end=None, pad=None):
+        ''' Convert to binary form.
+        @param  start   start address of output bytes.
+        @param  end     end address of output bytes.
+        @param  pad     fill empty spaces with this value
+                        (if None used self.padding).
+        @return         array of unsigned char data.
+        '''
+        if pad is None:
+            pad = self.padding
+
+        bin = array('B')
+
+        if self._buf == {}:
+            return bin
+
+        start, end = self._get_start_end(start, end)
+
+        for i in xrange(start, end+1):
+            bin.append(self._buf.get(i, pad))
+
+        return bin
+
+    def tobinstr(self, start=None, end=None, pad=0xFF):
+        ''' Convert to binary form.
+        @param  start   start address of output bytes.
+        @param  end     end address of output bytes.
+        @param  pad     fill empty spaces with this value
+                        (if None used self.padding).
+        @return         string of binary data.
+        '''
+        return self.tobinarray(start, end, pad).tostring()
+
+    def tobinfile(self, fobj, start=None, end=None, pad=0xFF):
+        '''Convert to binary and write to file.
+
+        @param  fobj    file name or file object for writing output bytes.
+        @param  start   start address of output bytes.
+        @param  end     end address of output bytes.
+        @param  pad     fill empty spaces with this value
+                        (if None used self.padding).
+        '''
+        if not hasattr(fobj, "write"):
+            fobj = file(fobj, "wb")
+            fclose = fobj.close
+        else:
+            fclose = None
+
+        fobj.write(self.tobinstr(start, end, pad))
+
+        if fclose:
+            fclose()
+
+    def minaddr(self):
+        ''' Get minimal address of HEX content. '''
+        aa = self._buf.keys()
+        if aa == []:
+            return 0
+        else:
+            return min(aa)
+
+    def maxaddr(self):
+        ''' Get maximal address of HEX content. '''
+        aa = self._buf.keys()
+        if aa == []:
+            return 0
+        else:
+            return max(aa)
+
+    def __getitem__(self, addr):
+        ''' Get byte from address.
+        @param  addr    address of byte.
+        @return         byte if address exists in HEX file, or self.padding
+                        if no data found.
+        '''
+        return self._buf.get(addr, self.padding)
+
+    def __setitem__(self, addr, byte):
+        self._buf[addr] = byte
+
+    def writefile(self, f, write_start_addr=True):
+        """Write data to file f in HEX format.
+
+        @param  f                   filename or file-like object for writing
+        @param  write_start_addr    enable or disable writing start address
+                                    record to file (enabled by default).
+                                    If there is no start address nothing
+                                    will be written.
+
+        @return True    if successful.
+        """
+        fwrite = getattr(f, "write", None)
+        if fwrite:
+            fobj = f
+            fclose = None
+        else:
+            fobj = file(f, 'w')
+            fwrite = fobj.write
+            fclose = fobj.close
+
+        # start address record if any
+        if self.start_addr and write_start_addr:
+            keys = self.start_addr.keys()
+            keys.sort()
+            bin = array('B', '\0'*9)
+            if keys == ['CS','IP']:
+                # Start Segment Address Record
+                bin[0] = 4      # reclen
+                bin[1] = 0      # offset msb
+                bin[2] = 0      # offset lsb
+                bin[3] = 3      # rectyp
+                cs = self.start_addr['CS']
+                bin[4] = (cs >> 8) & 0x0FF
+                bin[5] = cs & 0x0FF
+                ip = self.start_addr['IP']
+                bin[6] = (ip >> 8) & 0x0FF
+                bin[7] = ip & 0x0FF
+                bin[8] = (-sum(bin)) & 0x0FF    # chksum
+                fwrite(':')
+                fwrite(hexlify(bin.tostring()).upper())
+                fwrite('\n')
+            elif keys == ['EIP']:
+                # Start Linear Address Record
+                bin[0] = 4      # reclen
+                bin[1] = 0      # offset msb
+                bin[2] = 0      # offset lsb
+                bin[3] = 5      # rectyp
+                eip = self.start_addr['EIP']
+                bin[4] = (eip >> 24) & 0x0FF
+                bin[5] = (eip >> 16) & 0x0FF
+                bin[6] = (eip >> 8) & 0x0FF
+                bin[7] = eip & 0x0FF
+                bin[8] = (-sum(bin)) & 0x0FF    # chksum
+                fwrite(':')
+                fwrite(hexlify(bin.tostring()).upper())
+                fwrite('\n')
+            else:
+                self.Error = ('Invalid start address value: %r'
+                              % self.start_addr)
+                return False
+
+        # data
+        minaddr = IntelHex.minaddr(self)
+        maxaddr = IntelHex.maxaddr(self)
+        if maxaddr > 65535:
+            offset = (minaddr/65536)*65536
+        else:
+            offset = None
+
+        while True:
+            if offset != None:
+                # emit 32-bit offset record
+                high_ofs = offset / 65536
+                offset_record = ":02000004%04X" % high_ofs
+                bytes = divmod(high_ofs, 256)
+                csum = 2 + 4 + bytes[0] + bytes[1]
+                csum = (-csum) & 0x0FF
+                offset_record += "%02X\n" % csum 
+
+                ofs = offset
+                if (ofs + 65536) > maxaddr:
+                    rng = xrange(maxaddr - ofs + 1)
+                else:
+                    rng = xrange(65536)
+            else:
+                ofs = 0
+                offset_record = ''
+                rng = xrange(maxaddr + 1)
+
+            csum = 0
+            k = 0
+            record = ""
+            for addr in rng:
+                byte = self._buf.get(ofs+addr, None)
+                if byte != None:
+                    if k == 0:
+                        # optionally offset record
+                        fobj.write(offset_record)
+                        offset_record = ''
+                        # start data record
+                        record += "%04X00" % addr
+                        bytes = divmod(addr, 256)
+                        csum = bytes[0] + bytes[1]
+
+                    k += 1
+                    # continue data in record
+                    record += "%02X" % byte
+                    csum += byte
+
+                    # check for length of record
+                    if k < 16:
+                        continue
+
+                if k != 0:
+                    # close record
+                    csum += k
+                    csum = (-csum) & 0x0FF
+                    record += "%02X" % csum
+                    fobj.write(":%02X%s\n" % (k, record))
+                    # cleanup
+                    csum = 0
+                    k = 0
+                    record = ""
+            else:
+                if k != 0:
+                    # close record
+                    csum += k
+                    csum = (-csum) & 0x0FF
+                    record += "%02X" % csum
+                    fobj.write(":%02X%s\n" % (k, record))
+
+            # advance offset
+            if offset is None:
+                break
+
+            offset += 65536
+            if offset > maxaddr:
+                break
+
+        # end-of-file record
+        fobj.write(":00000001FF\n")
+        if fclose:
+            fclose()
+
+        return True
+#/IntelHex
+
+
+class IntelHex16bit(IntelHex):
+    """Access to data as 16-bit words."""
+
+    def __init__(self, source):
+        """Construct class from HEX file
+        or from instance of ordinary IntelHex class.
+
+        @param  source  file name of HEX file or file object
+                        or instance of ordinary IntelHex class
+        """
+        if isinstance(source, IntelHex):
+            # from ihex8
+            self.Error = source.Error
+            self.AddrOverlap = source.AddrOverlap
+            self.padding = source.padding
+    
+            # private members
+            self._fname = source._fname
+            self._buf = source._buf
+            self._readed = source._readed
+            self._eof = source._eof
+            self._offset = source._offset
+        else:
+            IntelHex.__init__(self, source)
+
+        if self.padding == 0x0FF:
+            self.padding = 0x0FFFF
+
+    def __getitem__(self, addr16):
+        """Get 16-bit word from address.
+        Raise error if found only one byte from pair.
+
+        @param  addr16  address of word (addr8 = 2 * addr16).
+        @return         word if bytes exists in HEX file, or self.padding
+                        if no data found.
+        """
+        addr1 = addr16 * 2
+        addr2 = addr1 + 1
+        byte1 = self._buf.get(addr1, None)
+        byte2 = self._buf.get(addr2, None)
+
+        if byte1 != None and byte2 != None:
+            return byte1 | (byte2 << 8)     # low endian
+
+        if byte1 == None and byte2 == None:
+            return self.padding
+
+        raise Exception, 'Bad access in 16-bit mode (not enough data)'
+
+    def __setitem__(self, addr16, word):
+        addr_byte = addr16 * 2
+        bytes = divmod(word, 256)
+        self._buf[addr_byte] = bytes[1]
+        self._buf[addr_byte+1] = bytes[0]
+
+    def minaddr(self):
+        '''Get minimal address of HEX content in 16-bit mode.'''
+        aa = self._buf.keys()
+        if aa == []:
+            return 0
+        else:
+            return min(aa)/2
+
+    def maxaddr(self):
+        '''Get maximal address of HEX content in 16-bit mode.'''
+        aa = self._buf.keys()
+        if aa == []:
+            return 0
+        else:
+            return max(aa)/2
+
+#/class IntelHex16bit
+
+
+def hex2bin(fin, fout, start=None, end=None, size=None, pad=0xFF):
+    """Hex-to-Bin convertor engine.
+    @return     0   if all OK
+
+    @param  fin     input hex file (filename or file-like object)
+    @param  fout    output bin file (filename or file-like object)
+    @param  start   start of address range (optional)
+    @param  end     end of address range (optional)
+    @param  size    size of resulting file (in bytes) (optional)
+    @param  pad     padding byte (optional)
+    """
+    h = IntelHex(fin)
+    if not h.readfile():
+        print "Bad HEX file"
+        return 1
+
+    # start, end, size
+    if size != None and size != 0:
+        if end == None:
+            if start == None:
+                start = h.minaddr()
+            end = start + size - 1
+        else:
+            if (end+1) >= size:
+                start = end + 1 - size
+            else:
+                start = 0
+
+    try:
+        h.tobinfile(fout, start, end, pad)
+    except IOError:
+        print "Could not write to file: %s" % fout
+        return 1
+
+    return 0
+#/def hex2bin
+
+
+if __name__ == '__main__':
+    import getopt
+    import os
+    import sys
+
+    usage = '''Hex2Bin python converting utility.
+Usage:
+    python intelhex.py [options] file.hex [out.bin]
+
+Arguments:
+    file.hex                name of hex file to processing.
+    out.bin                 name of output file.
+                            If omitted then output write to file.bin.
+
+Options:
+    -h, --help              this help message.
+    -p, --pad=FF            pad byte for empty spaces (ascii hex value).
+    -r, --range=START:END   specify address range for writing output
+                            (ascii hex value).
+                            Range can be in form 'START:' or ':END'.
+    -l, --length=NNNN,
+    -s, --size=NNNN         size of output (decimal value).
+'''
+
+    pad = 0xFF
+    start = None
+    end = None
+    size = None
+
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "hp:r:l:s:",
+                                  ["help", "pad=", "range=",
+                                   "length=", "size="])
+
+        for o, a in opts:
+            if o in ("-h", "--help"):
+                print usage
+                sys.exit(0)
+            elif o in ("-p", "--pad"):
+                try:
+                    pad = int(a, 16) & 0x0FF
+                except:
+                    raise getopt.GetoptError, 'Bad pad value'
+            elif o in ("-r", "--range"):
+                try:
+                    l = a.split(":")
+                    if l[0] != '':
+                        start = int(l[0], 16)
+                    if l[1] != '':
+                        end = int(l[1], 16)
+                except:
+                    raise getopt.GetoptError, 'Bad range value(s)'
+            elif o in ("-l", "--lenght", "-s", "--size"):
+                try:
+                    size = int(a, 10)
+                except:
+                    raise getopt.GetoptError, 'Bad size value'
+
+        if start != None and end != None and size != None:
+            raise getopt.GetoptError, 'Cannot specify START:END and SIZE simultaneously'
+
+        if not args:
+            raise getopt.GetoptError, 'Hex file is not specified'
+
+        if len(args) > 2:
+            raise getopt.GetoptError, 'Too many arguments'
+
+    except getopt.GetoptError, msg:
+        print msg
+        print usage
+        sys.exit(2)
+
+    fin = args[0]
+    if len(args) == 1:
+        import os.path
+        name, ext = os.path.splitext(fin)
+        fout = name + ".bin"
+    else:
+        fout = args[1]
+
+    if not os.path.isfile(fin):
+        print "File not found"
+        sys.exit(1)
+
+    sys.exit(hex2bin(fin, fout, start, end, size, pad))

+ 362 - 0
j1/firmware/invaders.fs

@@ -0,0 +1,362 @@
+( Space invaders                             JCB 10:43 11/18/10)
+
+: whereis ( t -- x y ) 
+    >r
+    d# 384 r@ sin* d# 384 +
+    r@ d# 4 rshift d# 32 r> 2* sin* +
+;
+
+56 constant nsprites
+
+nsprites array invx
+nsprites array invy
+nsprites array alive
+nsprites array invnext
+nsprites array anim
+
+: invload ( i -- ) \ load sprite i
+    \ s" sprite " type dup . s"  at " type dup invx @ . dup invy @ . cr
+    dup invx @ swap
+    dup invy @ swap
+    dup anim @ swap
+    d# 7 and
+    tuck cells vga_spritep + !
+    sprite!
+;
+
+: inv-makedl ( -- )
+    erasedl
+    nsprites 0do
+        \ invy -ve load sprite; +ve gives the dl offset
+        i alive @ if
+            i invy @ dup 0< if
+                drop i invload
+            else
+                dup d# 512 < if
+                    \ dl[y] -> invnext[i]
+                    \ i -> dl[y]
+                    cells dl + dup
+                    @ i invnext !
+                    i swap !
+                else
+                    drop
+                then
+            then
+        then
+    loop
+;
+
+: inv-chase
+    d# 512 0do
+        begin vga-line@ i = until
+        \ s" line" type i . cr
+        i cells dl + @
+        begin
+            dup d# 0 >=
+        while
+            dup invload
+            invnext @
+        repeat
+    loop
+;
+
+: born ( x y i ) \ sprite i born
+    dup alive on
+    tuck invy !
+    invx !
+;
+
+: kill ( i -- ) \ kill sprite i
+    d# 512 over invy !
+    alive off
+;
+
+: isalien   ( u -- f)
+    d# 6 and d# 6 <> ;
+
+: moveto ( i -- ) \ move invader i to current position
+    dup d# 6 and d# 6 <>
+    over alive @ and if
+        >r
+        frame @ r@ d# 7 and d# 8 * + whereis
+        r@ d# 3 rshift d# 40 * +
+        r@ invy !
+        r> invx !
+    else
+        drop
+    then
+;
+
+: bomb ( u -- u ) d# 3 lshift d# 6 + ;
+: shot ( u -- u ) d# 3 lshift d# 7 + ;
+
+8 array lowest
+
+: findlowest
+    d# 8 0do d# -1 i lowest ! loop
+    d# 48 0do
+        i alive @ if
+            i dup d# 7 and lowest !
+        then
+    loop
+;
+
+create bias 0 , 1 , 2 , 3 , 4 , 5 , 0 , 5 ,
+: rand6
+    time @ d# 7 and cells bias + @
+;
+
+2variable bombalarm
+variable nextbomb
+
+2variable shotalarm
+variable nextshot
+
+variable playerx
+variable lives
+2variable score
+variable dying
+
+32 constant girth
+
+: 1+mod6 ( a )
+    dup @ dup d# 5 = if d# -5 else d# 1 then + swap ! ;
+
+: .status
+    'emit @ >r ['] vga-emit 'emit !
+
+    home
+    s" LIVES " type lives @ .
+    d# 38 d# 0 vga-at-xy
+    s" SCORE " type score 2@ <# # # # # # # #> type
+    cr
+
+    lives @ 0= if
+        ['] vga-bigemit 'emit !
+        d# 8 d# 7  vga-at-xy s" GAME" type
+        d# 8 d# 17 vga-at-xy s" OVER" type
+    then
+
+    r> 'emit !
+;
+
+: newlife
+    d# -1 lives +! .status
+    d# 0 dying !
+    d# 100 playerx !
+;
+
+: parabolic ( dx dy i -- ) \ move sprite i in parabolic path
+    >r
+    swap r@ invx +!
+    dying @ d# 3 rshift +
+    r> invy +!
+;
+
+: exploding
+    d# 3  d# -4 d# 48 parabolic
+    d# -3 d# -4 d# 49 parabolic
+    d# -4 d# -3 d# 50 parabolic
+    d# 4  d# -3 d# 51 parabolic
+    d# -5 d# -2 d# 52 parabolic
+    d# 5  d# -2 d# 53 parabolic
+    d# 1  d# -2 d# 55 parabolic
+;
+
+: @xy ( i -- x y )
+    dup invx @ swap invy @ ;
+
+: dist ( u1 u2 )
+    invert + dup 0< xor ;
+
+: fall
+    d# 6 0do
+        i bomb
+        d# 4 over invy +!
+        @xy d# 470 dist d# 16 < swap
+        playerx @ dist girth < and
+        dying @ 0= and if
+            d# 1 dying !
+        then
+    loop
+;
+
+: trigger \ if shotalarm expired, launch new shot
+    shotalarm isalarm if
+        d# 400000. shotalarm setalarm
+        playerx @ d# 480
+        nextshot @ shot born
+        nextshot 1+mod6
+    then
+;
+
+: collide ( x y -- u )
+    d# 48 0do
+        i isalien i alive @ and if
+            over i invx @ dist d# 16 <
+            over i invy @ dist d# 16 < and if
+                2drop i unloop exit
+            then
+        then
+    loop
+    2drop
+    d# -1
+;
+
+: rise
+    d# 6 0do
+        i shot >r r@ alive @ if
+            d# -5 r@ invy +!
+            r@ invy @ d# -30 < if r@ kill then
+            r@ @xy collide dup 0< if
+                drop
+            else
+                kill r@ kill
+                d# 10. score 2@ d+ score 2!
+                .status
+            then
+        then
+        r> drop
+    loop
+;
+
+: doplayer
+    lives @ if
+        dying @ 0= if
+            buttons >r
+
+            girth 2/ playerx @ <
+            r@ pb2 and and if
+                d# -4 playerx +!
+            then
+
+            playerx @ d# 800 girth 2/ - <
+            r@ pb3 and and if
+                d# 4 playerx +!
+            then
+
+            r> pb4 and if
+                trigger
+            \ else trigger
+            then
+
+            d# 6 0do
+                frame @ d# 3 lshift i d# 42 * +
+                girth swap sin* playerx @ +
+                d# 480
+                i d# 48 +
+                dup anim on
+                born
+            loop
+            playerx @ d# 470 d# 55 born
+        else
+            exploding
+            d# 1 dying +!
+            dying @ d# 100 > if
+                newlife
+            then
+        then
+    then
+;
+
+create cscheme
+    h# 400 ,
+    h# 440 ,
+    h# 040 ,
+    h# 044 ,
+    h# 004 ,
+    h# 404 ,
+    h# 340 ,
+    h# 444 ,
+
+: invaders-cold
+    vga-page
+    d# 16384 0do
+        h# 208000. 2/ i s>d d+ flash@
+        i vga_spritea !  vga_spriteport !
+    loop
+
+    vga_addsprites on
+    rainbow
+
+    \ vga_spritep d# 6 cells + on
+
+    \ everything dead
+    nsprites 0do
+        i kill
+    loop
+
+    \ all aliens alive
+    d# 48 0do 
+        i isalien i alive !
+    loop
+
+    d# 500000. bombalarm setalarm
+    d# 0 nextbomb !
+    d# 100000. shotalarm setalarm
+    d# 0 nextshot !
+    d# 4 lives !
+    d# 0. score 2!
+
+    newlife
+
+    time@ xor seed !
+    d# 0 frame !
+    d# 48 0do i moveto loop
+;
+
+0 [IF]
+: escape
+    vision isalarm next? or ;
+: restart
+    vision isalarm sw2_n @ 0= or ;
+[ELSE]
+: escape
+    next? ;
+: restart
+    sw2_n @ 0= ;
+[THEN]
+
+: gameloop
+    invaders-cold
+    begin
+depth if snap then
+        inv-makedl
+depth if snap then
+        inv-chase
+depth if snap then
+        frame @ 1+ frame !
+        d# 48 0do i moveto loop
+        findlowest
+        bombalarm isalarm if
+            d# 800000. bombalarm setalarm
+            rand6 lowest @ dup 0< if
+                drop
+            else
+                dup invx @ swap invy @
+                dup d# 460 > if d# 1 dying ! then
+                nextbomb @ bomb born
+                nextbomb 1+mod6
+            then
+        then
+depth if snap then
+        fall
+depth if snap then
+        rise
+depth if snap then
+        doplayer
+depth if snap then
+        escape if exit then
+    again
+;
+
+: invaders-main
+    invaders-cold
+    d# 9000000. vision setalarm
+
+    gameloop
+    snap
+
+    frame @ . s"  frames" type cr
+;
+

+ 124 - 0
j1/firmware/ip.fs

@@ -0,0 +1,124 @@
+( IP networking: headers and wrapup         JCB 13:21 08/24/10)
+module[ ip"
+
+: ip-datalength ( -- u ) \ length of current IP packet in words
+    ETH.IP.LENGTH packet@
+    d# 20 - 2/
+;
+
+: ip-isproto ( u -- f ) \ true if packet PROTO is u
+    ETH.IP.TTLPROTO packet@ h# ff and =
+;
+
+: ip-identification
+    ip-id-counter d# 1 over +! @
+;
+
+: @ethaddr ( eth-addr -- mac01 mac23 mac45 )
+    ?dup
+    if
+        dup @ swap 2+ 2@
+    else
+        ethaddr-broadcast
+    then
+;
+
+: ip-header ( dst-ip src-ip eth-addr protocol -- )
+    >r
+    mac-pkt-begin
+
+    @ethaddr mac-pkt-3,
+    net-my-mac mac-pkt-3,
+    h# 800 mac-pkt-,
+
+    h# 4500
+    h# 0000                  \  length
+    ip-identification
+    mac-pkt-3,
+    h# 4000                  \  do not fragment
+    h# 4000 r> or            \  TTL, protocol
+    d# 0                        \  checksum
+    mac-pkt-3,
+    mac-pkt-2,              \  src ip
+    mac-pkt-2,              \  dst ip
+;
+
+: ip-wrapup ( bytelen -- )
+    \  write IP length
+    ETH.IP -
+    ETH.IP.LENGTH packetout-off mac!
+
+    \  write IP checksum
+    ETH.IP packetout-off d# 10 mac-checksum
+    ETH.IP.CHKSUM packetout-off mac!
+;
+
+: ip-packet-srcip
+    d# 2 ETH.IP.SRCIP mac-inoffset mac@n
+;
+
+( ICMP return and originate                  JCB 13:22 08/24/10)
+
+\  Someone pings us, generate a return packet
+
+: icmp-handler
+    IP_PROTO_ICMP ip-isproto
+    ETH.IP.ICMP.TYPECODE packet@ h# 800 =
+    and if
+        ip-packet-srcip
+        2dup arp-lookup
+        ?dup if
+            \  transmit ICMP reply
+                                    \  dstip *ethaddr
+            net-my-ip rot           \  dstip srcip *ethaddr
+            d# 1 ip-header
+
+            \  Now the ICMP header
+            d# 0 mac-pkt-,
+
+            s" =====> ICMP seq " type
+            ETH.IP.ICMP.SEQUENCE mac-inoffset mac@ u. cr
+
+            ETH.IP.ICMP.IDENTIFIER mac-inoffset
+            ip-datalength 2-        ( offset n )
+            tuck
+            mac-checksum mac-pkt-,
+            ETH.IP.ICMP.IDENTIFIER mac-pkt-src
+
+            mac-pkt-complete
+            ip-wrapup
+            mac-send
+        else
+            2drop
+        then
+    then
+;
+    
+: ping ( ip. -- ) \ originate
+    2dup arp-lookup
+    ?dup if
+        \  transmit ICMP request
+                                \  dstip *ethaddr
+        net-my-ip rot           \  dstip srcip *ethaddr
+        d# 1 ip-header
+
+        \  Now the ICMP header
+        h# 800 mac-pkt-,
+
+        \  id is h# 550b, seq is lo word of time
+        h# 550b time@ drop
+        2dup +1c h# 800 +1c
+        d# 28 begin swap d# 0 +1c swap 1- dup 0= until drop
+        invert mac-pkt-,     \  checksum
+        mac-pkt-2,
+        d# 28 mac-pkt-,0
+
+        mac-pkt-complete
+        ip-wrapup
+        mac-send
+    else
+        2drop
+    then
+;
+
+]module

+ 70 - 0
j1/firmware/ip0.fs

@@ -0,0 +1,70 @@
+( Variables for IP networking                JCB 13:21 08/24/10)
+
+module[ ip0"
+create ip-id-counter    d# 2 allot
+create ip-addr          d# 4 allot
+create ip-router        d# 4 allot
+create ip-subnetmask    d# 4 allot
+create ip-dns           d# 4 allot
+create icmp-alarm-ptr   d# 1 allot
+
+: ethaddr-broadcast
+    h# ffff dup dup
+;
+
+: net-my-ip
+    ip-addr 2@
+;
+
+: ethaddr-pretty-w
+    dup endian hex2
+    [char] : emit
+    hex2
+;
+
+: ethaddr-pretty
+    swap rot
+    ethaddr-pretty-w [char] : emit
+    ethaddr-pretty-w [char] : emit
+    ethaddr-pretty-w
+;
+
+: ip-pretty-byte
+    h# ff and
+    \ d# 0 u.r
+    hex2
+;
+
+: ip-pretty-2
+    dup swab ip-pretty-byte [char] . emit ip-pretty-byte
+;
+
+: ip-pretty
+    swap
+    ip-pretty-2 [char] . emit
+    ip-pretty-2
+;
+
+( IP address literals                        JCB 14:30 10/26/10)
+
+================================================================
+
+It is neat to write IP address literals e.g.
+ip# 192.168.0.1
+
+================================================================
+
+meta
+
+: octet# ( c -- u ) 0. rot parse >number throw 2drop ;
+
+: ip# 
+    [char] . octet# 8 lshift
+    [char] . octet# or do-number
+    [char] . octet# 8 lshift
+    bl octet#       or do-number
+;
+
+target
+
+]module

BIN
j1/firmware/j1.png


+ 28 - 0
j1/firmware/keycodes.fs

@@ -0,0 +1,28 @@
+9  constant TAB
+10 constant ENTER
+27 constant ESC
+
+h# 80 constant KDEL
+
+h# 81 constant KF1
+h# 82 constant KF2
+h# 83 constant KF3
+h# 84 constant KF4
+h# 85 constant KF5
+h# 86 constant KF6
+h# 87 constant KF7
+h# 88 constant KF8
+h# 89 constant KF9
+h# 8a constant KF10
+h# 8b constant KF11
+h# 8c constant KF12
+
+h# 90 constant KHOME
+h# 91 constant KPGUP
+h# 92 constant KPGDN
+h# 93 constant KEND
+h# 94 constant KLEFT
+h# 95 constant KRIGHT
+h# 96 constant KUP
+h# 97 constant KDOWN
+h# 98 constant KINS

+ 114 - 0
j1/firmware/loader.fs

@@ -0,0 +1,114 @@
+( LOADER PROTOCOL                            JCB 09:16 11/11/10)
+
+947 constant PORT
+
+: response0 ( -- )
+    ETH.IP.UDP.SOURCEPORT packet@ 
+    PORT
+    d# 2 ETH.IP.SRCIP mac-inoffset mac@n  
+    net-my-ip
+    2over arp-lookup
+    ( dst-port src-port dst-ip src-ip *ethaddr )
+    udp-header
+    d# 0 mac-pkt-,
+    ETH.IP.UDP.LOADER.SEQNO packet@ mac-pkt-,
+;
+
+: response1
+    udp-wrapup mac-send
+;
+
+: respond
+    response0
+    response1
+;
+
+: ramread
+    response0
+    ETH.IP.UDP.LOADER.RAMREAD.ADDR packet@
+    d# 128 bounds begin
+        dup @ mac-pkt-,
+        cell+
+        2dup=
+    until
+    2drop
+    response1
+;
+
+: ramwrite
+    ETH.IP.UDP.LOADER.RAMWRITE.ADDR packet@ 
+    d# 64 0do
+        ETH.IP.UDP.LOADER.RAMWRITE.DATA i cells + packet@
+        over !
+        cell+
+    loop
+    drop
+    respond
+;
+
+: reboot
+    respond bootloader ;
+
+: flashread
+    response0
+    ETH.IP.UDP.LOADER.FLASHREAD.ADDR packetd@ d2/
+    flash-reset
+    d# 64 0do
+        2dup flash@
+        mac-pkt-,
+        d1+
+    loop
+    2drop
+    response1
+;
+
+: flasherase
+    respond flash-chiperase ;
+
+: flashdone
+    response0
+    ETH.IP.UDP.LOADER.FLASHREAD.ADDR packetd@ d2/
+    flash-erased mac-pkt-,
+    response1
+;
+
+: flashwrite
+    ETH.IP.UDP.LOADER.FLASHWRITE.ADDR packetd@ d2/
+    d# 64 0do
+        2dup
+        ETH.IP.UDP.LOADER.FLASHWRITE.DATA i cells + packet@
+        -rot flash!
+        d1+
+    loop
+    2drop
+    respond
+;
+
+: flashsectorerase
+    ETH.IP.UDP.LOADER.FLASHWRITE.ADDR packetd@ d2/
+    flash-sectorerase
+    respond
+;
+
+jumptable opcodes
+( 0 ) | ramread
+( 1 ) | ramwrite
+( 2 ) | reboot
+( 3 ) | flashread
+( 4 ) | flasherase
+( 5 ) | flashdone
+( 6 ) | flashwrite
+( 7 ) | flashsectorerase
+
+: loader-handler ( -- )
+    IP_PROTO_UDP ip-isproto if
+        ETH.IP.UDP.DESTPORT packet@ PORT =
+        d# 2 ETH.IP.SRCIP mac-inoffset mac@n arp-lookup 0<> and if
+            udp-checksum? if
+                ETH.IP.UDP.LOADER.OPCODE packet@ 
+                \ s" loader opcode=" type dup hex4 cr
+                opcodes execute
+            then
+        then
+    then
+;

+ 799 - 0
j1/firmware/main.fs

@@ -0,0 +1,799 @@
+( Main for WGE firmware                      JCB 13:24 08/24/10)
+
+\ warnings off
+\ require tags.fs
+
+include crossj1.fs
+meta
+    : TARGET? 1 ;
+    : build-debug? 1 ;
+
+include basewords.fs
+target
+include hwdefs.fs
+
+0 [IF]
+    h# 1f80 org
+    \ the RAM Bootloader copies 2000-3f80 to 0-1f80, then branches to zero
+    : bootloader
+        h# 1f80 h# 0
+        begin
+            2dupxor
+        while
+            dup h# 2000 + @
+            over !
+            d# 2 +
+        repeat
+
+        begin dsp h# ff and while drop repeat
+        d# 0 >r
+    ;
+[ELSE]
+    h# 3f80 org
+    \ the Flash Bootloader copies 0x190000 to 0-3f80, then branches to zero
+    : bootloader
+        h# c flash_a_hi !
+        h# 0 begin
+            dup h# 8000 + flash_a !
+            d# 0 flash_oe_n !
+            flash_d @
+            d# 1 flash_oe_n !
+            over dup + !
+            d# 1 +
+            dup h# 1fc0 =
+        until
+
+        begin dsp h# ff and while drop repeat
+        d# 0 >r
+    ;
+[THEN]
+
+4 org
+module[ everything"
+include nuc.fs
+
+include version.fs
+
+\ 33333333 / 115200 = 289, half cycle is 144
+
+: pause144
+    d# 0 d# 45
+    begin
+        1-
+        2dup=
+    until
+    2drop
+;
+
+: serout ( u -- )
+    h# 300 or   \ 1 stop bits
+    2*          \ 0 start bit
+    \ Start bit
+    begin
+        dup RS232_TXD ! 2/
+        pause144
+        pause144
+        dup 0=
+    until
+    drop
+    pause144 pause144
+    pause144 pause144
+;
+
+: frac ( ud u -- d1 u1 ) \ d1+u1 is ud
+    >r 2dup d# 1 r@ m*/ 2swap 2over r> d# 1 m*/ d- drop ;
+: .2  s>d <# # # #> type ;
+: build.
+    decimal
+    builddate drop
+    [ -8 3600 * ] literal s>d d+
+    d# 1 d# 60 m*/mod >r
+    d# 1 d# 60 m*/mod >r
+    d# 1 d# 24 m*/mod >r
+    2drop
+    r> .2 [char] : emit
+    r> .2 [char] : emit
+    r> .2 ;
+
+: net-my-mac h# 1234 h# 5677 h# 7777 ;
+
+include doc.fs
+include time.fs
+include eth-ax88796.fs
+include packet.fs
+include ip0.fs
+include defines_tcpip.fs
+include defines_tcpip2.fs
+include arp.fs
+include ip.fs
+include udp.fs
+include dhcp.fs
+
+code in end-code
+: on ( a -- ) d# 1 swap ! ;
+code out end-code
+: off ( a -- ) d# 0 swap ! ;
+
+: flash-reset
+    flash_rst_n   off
+    flash_rst_n   on
+;
+
+: flash-cold
+    flash_ddir    on
+    flash_ce_n    off
+    flash_oe_n    on
+    flash_we_n    on
+    flash_byte_n  on
+    flash_rdy     on
+    flash-reset
+;
+
+: flash-w ( u a -- )
+    flash_a !
+    flash_d !
+    flash_ddir off
+    flash_we_n off
+    flash_we_n on
+    flash_ddir on
+;
+
+: flash-r ( a -- u )
+    flash_a !
+    flash_oe_n off
+    flash_d @
+    flash_oe_n on
+;
+
+: flash-unlock ( -- )
+    h# aa h# 555 flash-w
+    h# 55 h# 2aa flash-w
+;
+
+: flash! ( u da. -- )
+    flash-unlock
+    h# a0 h# 555 flash-w
+    flash_a 2+ !    ( u a )
+    2dup            ( u a u a)
+    flash-w         ( u a )
+    begin
+        2dup flash-r xor
+        h# 80 and 0=
+    until
+    2drop
+    flash-reset
+;
+
+: flash@ ( da. -- u )
+    flash_a 2+ !    ( u a )
+    flash-r
+;
+
+: flash-chiperase
+    flash-unlock
+    h# 80 h# 555 flash-w
+    h# aa h# 555 flash-w
+    h# 55 h# 2aa flash-w
+    h# 10 h# 555 flash-w
+;
+
+: flash-sectorerase ( da -- ) \ erase one sector
+    flash-unlock
+    h# 80 h# 555 flash-w
+    h# aa h# 555 flash-w
+    h# 55 h# 2aa flash-w
+    flash_a 2+ ! h# 30 swap flash-w
+;
+
+: flash-erased ( a -- f )
+    flash@ h# 80 and 0<> ;
+
+: flash-dump ( da u -- )
+    0do
+        2dup flash@ hex4 space
+        d1+
+    loop cr
+    2drop
+;
+
+: flashc@
+    over d# 15 lshift flash_d !
+    d2/ flash@
+;
+
+: flash-bytes
+    s" BYTES: " type
+    flash_byte_n  off
+    h# 0.
+    d# 1024 0do
+        i d# 15 and 0= if
+            cr
+            2dup hex8 space space
+        then
+        2dup flashc@ hex2 space
+        d1+
+    loop cr
+    2drop
+    flash_byte_n  on
+;
+
+0 [IF]
+: flash-demo
+    flash-unlock
+    h# 90 h# 555 flash-w
+    h# 00 flash-r hex4 cr
+    flash-reset
+
+    false if
+        flash-unlock
+        h# a0 h# 555 flash-w
+        h# 0947 h# 5 flash-w
+        sleep1
+        flash-reset
+    then
+
+    \ h# dead d# 11. flash!
+
+    h# 100 0do
+        i flash-r hex4 space
+    loop cr
+    cr cr
+    d# 0. h# 80 flash-dump
+    cr cr
+
+    flash-bytes
+
+    exit
+    flash-unlock
+    h# 80 h# 555 flash-w
+    h# aa h# 555 flash-w
+    h# 55 h# 2aa flash-w
+    h# 10 h# 555 flash-w
+    s" waiting for erase" type cr
+    begin
+        h# 0 flash-r dup hex4 cr
+        h# 80 and
+    until
+
+    h# 100 0do
+        i flash-r hex4 space
+    loop cr
+;
+[THEN]
+
+include sprite.fs
+
+variable cursory \ ptr to start of line in video memory
+variable cursorx \ offset to char
+
+64 constant width
+50 constant wrapcolumn
+
+: vga-at-xy ( u1 u2 )
+    cursory !
+    cursorx !
+;
+
+: home  d# 0 vga_scroll ! d# 0 d# 0 vga-at-xy ;
+
+: vga-line ( -- a ) \ address of current line
+    cursory @ vga_scroll @ + d# 31 and d# 6 lshift 
+    h# 8000 or
+;
+
+: vga-erase ( a u -- )
+    bounds begin
+        2dupxor
+    while
+        h# 00 over ! 1+
+    repeat 2drop
+;
+
+: vga-page
+    home vga-line d# 2048 vga-erase
+    hide
+;
+
+: down1
+    cursory @ d# 31 <> if
+        d# 1 cursory +!
+    else
+        false if
+            d# 1 vga_scroll +!
+            vga-line width vga-erase
+        else
+            home
+        then
+    then
+;
+
+: vga-emit ( c -- )
+    dup d# 13 = if
+        drop d# 0 cursorx !
+    else
+        dup d# 10 = if
+            drop down1
+        else
+            d# -32 +
+            vga-line cursorx @ + !
+            d# 1 cursorx +!
+            cursorx @ wrapcolumn = if
+                d# 0 cursorx !
+                down1
+            then
+        then
+    then
+;
+
+: flash>ram ( d. a -- ) \ copy 2K from flash d to a
+    >r d2/ r>
+    d# 1024 0do
+        >r
+        2dup flash@
+        r> ( d. u a )
+        over swab over !
+        1+
+        tuck !
+        1+
+        >r d1+ r>
+    loop
+    drop 2drop
+;
+
+: vga-cold
+    h# f800 h# f000 do
+        d# 0 i !
+    loop
+
+    vga-page
+
+    \ pic: Copy 2048 bytes from 180000 to 8000
+    \ chr: Copy 2048 bytes from 180800 to f000
+    h# 180000. h# 8000 flash>ram
+    h# 180800. h# f000 flash>ram
+
+    \ ['] vga-emit 'emit !
+;
+
+create glyph 8 allot
+: wide1 ( c -- )
+    swab
+    d# 8 0do
+        dup 0<
+        if d# 127 else sp then
+        \ if [char] * else [char] . then
+        vga-emit
+        2*
+    loop drop
+;
+
+: vga-bigemit ( c -- )
+    dup d# 13 = if
+        drop d# 0 cursorx !
+    else
+        dup d# 10 = if
+            drop d# 8 0do down1 loop
+        else
+            sp - d# 8 * s>d
+            h# 00180800. d+ d2/
+            d# 4 0do
+                2dup flash@ swab
+                i cells glyph + !
+                d1+
+            loop 2drop
+
+            d# 7 0do
+                i glyph + c@ wide1
+                d# -8 cursorx +! down1
+            loop
+            d# 7 glyph + c@ wide1
+
+            d# -7 cursory +!
+        then
+    then
+;
+
+( Demo utilities                             JCB 10:56 12/05/10)
+
+: statusline ( a u -- ) \ display string on the status line
+    d# 0 d# 31 2dup vga-at-xy
+    d# 50 spaces
+    vga-at-xy type
+;
+
+( Game stuff                                 JCB 15:20 11/15/10)
+
+variable seed
+: random  ( -- u )
+    seed @ d# 23947 * d# 57711 xor dup seed ! ;   
+
+
+\ Each line is 20.8 us, so 1000 instructions
+
+include sincos.fs
+
+( Stars                                      JCB 15:23 11/15/10)
+
+2variable vision
+variable frame
+128 constant nstars
+create stars 1024 allot
+
+: star 2* cells stars + ;
+: 15.*  m* d2* nip ;
+
+\ >>> math.cos(math.pi / 180) * 32767
+\ 32762.009427189474
+\ >>> math.sin(math.pi / 180) * 32767
+\ 571.8630017304688
+
+[ pi 128e0 f/ fcos 32767e0 f* f>d drop ] constant COSa
+[ pi 128e0 f/ fsin 32767e0 f* f>d drop ] constant SINa
+
+: rotate ( i -- ) \ rotate star i
+    star dup 2@ ( x y )
+    over SINa 15.* over COSa 15.* + >r
+    swap COSa 15.* swap SINa 15.* - r>
+    rot 2!
+;
+
+: rotateall
+    d# 256 0do i rotate loop ;
+
+: scatterR
+    nstars 0do
+        random d# 0 i star 2!
+        rotateall
+        rotateall
+        rotateall
+        rotateall
+    loop
+;
+
+: scatterSpiral
+    nstars 0do
+        i d# 3 and 1+ d# 8000 *
+        d# 0 i star 2!
+        rotateall
+        rotateall
+        rotateall
+        rotateall
+    loop
+;
+
+: scatter
+    nstars 0do
+        \ d# 0 random
+        d# 0 i sin
+        i star 2!
+        i random d# 255 and 0do
+            dup rotate
+        loop drop
+    loop
+;
+
+: /128  dup 0< h# fe00 and swap d# 7 rshift or ;
+: tx    /128 [ 400 ] literal + ;
+: ty    /128 [ 256 ] literal + ;
+
+: plot ( i s ) \ plot star i in sprite s
+    >r
+    dup star @ tx swap d# 2 lshift
+    r> sprite!
+;
+
+( Display list                               JCB 16:10 11/15/10)
+
+create dl 1026 allot
+
+: erasedl
+    dl d# 1024 bounds begin
+        d# -1 over !
+        cell+ 2dup=
+    until 2drop
+;
+
+: makedl
+    erasedl
+
+    nstars 0do
+        i d# 2 lshift
+        cells dl +
+        \ cell occupied, use one below
+        \ dup @ 0< invert if cell+ then
+        i swap !
+    loop
+;
+
+variable lastsp
+: stars-chasebeam
+    hide
+    d# 0 lastsp !
+    d# 512 0do
+        begin vga-line@ i = until
+        i cells dl + @ dup 0< if
+            drop
+        else
+            lastsp @ 1+ d# 7 and dup lastsp ! plot
+        then
+        i nstars < if i rotate then
+    loop
+;
+
+
+
+: loadcolors
+    d# 8 0do
+        dup @
+        i cells vga_spritec + !
+        cell+
+    loop
+    drop
+;
+create cpastels
+h# 423 ,
+h# 243 ,
+h# 234 ,
+h# 444 ,
+h# 324 ,
+h# 432 ,
+h# 342 ,
+h# 244 ,
+: pastels cpastels loadcolors ;
+
+create crainbow
+h# 400 ,
+h# 440 ,
+h# 040 ,
+h# 044 ,
+h# 004 ,
+h# 404 ,
+h# 444 ,
+h# 444 ,
+: rainbow crainbow loadcolors ;
+
+variable prev_sw3_n
+
+: next? ( -- f ) \ has user requested next screen
+    sw3_n @ prev_sw3_n fall?
+;
+
+: loadsprites ( da -- )
+    2/
+    d# 16384 0do
+        2dup i s>d d+ flash@
+        i vga_spritea !  vga_spriteport !
+    loop
+    2drop
+;
+
+: stars-main
+    vga-page
+    d# 16384 0do
+        h# 204000. 2/ i s>d d+ flash@
+        i vga_spritea !  vga_spriteport !
+    loop
+
+    vga_addsprites on
+    rainbow
+
+    time@ xor seed !
+    seed off
+    scatter
+
+    d# 7000000. vision setalarm
+    d# 0 frame !
+    begin
+        makedl
+        stars-chasebeam
+        \ d# 256 0do i i plot loop
+        \ rotateall
+        frame @ 1+ frame !
+        next?
+    until
+    frame @ . s"  frames" type cr
+;
+
+: buttons ( -- u ) \ pb4 pb3 pb2
+    pb_a_dir on
+    pb_a @ d# 7 xor
+    pb_a_dir off
+;
+
+include loader.fs
+include dns.fs
+
+: preip-handler
+    begin
+        mac-fullness
+    while
+        OFFSET_ETH_TYPE packet@ h# 800 = if
+            dhcp-wait-offer
+        then
+        mac-consume
+    repeat
+;
+
+: haveip-handler
+    \ time@ begin ether_irq @ until time@ 2swap d- d. cr
+    \ begin ether_irq @ until
+    begin
+        mac-fullness
+    while
+        arp-handler
+        OFFSET_ETH_TYPE packet@ h# 800 =
+        if
+            d# 2 OFFSET_IP_DSTIP mac-inoffset mac@n net-my-ip d=
+            if
+                icmp-handler
+            then
+            loader-handler
+        then
+        depth if .s cr then
+        mac-consume
+    repeat
+;
+
+include invaders.fs
+
+: uptime
+    time@
+    d# 1 d# 1000 m*/
+    d# 1 d# 1000 m*/
+;
+
+( IP address formatting                      JCB 14:50 10/26/10)
+
+: #ip1  h# ff and s>d #s 2drop ;
+: #.    [char] . hold ;
+: #ip2  dup #ip1 #. d# 8 rshift #ip1 ;
+: #ip   ( ip -- c-addr u) dup #ip2 #. over #ip2 ;
+
+variable prev_sw2_n
+: sw2?  sw2_n @ prev_sw2_n fall? ;
+
+include ps2kb.fs
+
+: istab?
+    key? dup if key TAB = and then
+;
+        
+: welcome-main
+    vga-cold
+    home
+    s" F1 to set up network, TAB for next demo" statusline
+
+    rainbow
+    h# 200000. loadsprites
+    'emit @ >r
+    d# 6 d# 26 vga-at-xy s" Softcore Forth CPU" type
+
+    d# 32 d# 6 vga-at-xy  s" version " type version type
+    d# 32 d# 8 vga-at-xy  s" built   " type build.
+
+    kb-cold
+    home
+    begin
+        kbfifo-proc
+        d# 32 d# 10 vga-at-xy net-my-ip <# #ip #> type space space
+        d# 32 d# 12 vga-at-xy s" uptime  " type uptime d.
+        haveip-handler
+
+        d# 8 0do
+            frame @ i d# 32 * + invert >r
+            d# 100 r@ sin* d# 600 +
+            d# 100 r> cos* d# 334 +
+            i sprite!
+        loop
+
+        waitblank
+        d# 1 frame +!
+        next?
+        istab? or
+    until
+    r> 'emit !
+;
+
+include clock.fs
+
+: frob
+    flash_ce_n    on
+    flash_ddir off
+    d# 32 0do
+        d# 1 i d# 7 and lshift
+        flash_d !
+        d# 30000. sleepus
+    loop
+    flash_ddir on
+;
+
+: main
+    decimal
+    ['] serout 'emit !
+    \ sleep1
+
+    frob
+
+    d# 60 0do cr loop
+    s" Welcome! Built " type build. cr 
+    snap
+
+    flash-cold
+    \ flash-demo
+    \ flash-bytes
+    vga-cold
+    ['] vga-emit 'emit !
+    s" Waiting for Ethernet NIC" statusline
+    mac-cold
+    nicwork
+    h# decafbad. dhcp-xid!
+    d# 3000000. dhcp-alarm setalarm
+    false if
+        ip-addr dz
+        begin
+            net-my-ip d0=
+        while
+            dhcp-alarm isalarm if
+                dhcp-discover
+                s" DISCOVER" type cr
+                d# 3000000. dhcp-alarm setalarm
+            then
+            preip-handler
+        repeat
+    else
+        ip# 192.168.0.99 ip-addr 2!
+        ip# 255.255.255.0 ip-subnetmask 2!
+        ip# 192.168.0.1 ip-router 2!
+        \ ip# 192.168.2.201 ip-addr 2!
+        \ ip# 255.255.255.0 ip-subnetmask 2!
+        \ ip# 192.168.2.1 ip-router 2!
+    then
+    dhcp-status
+    arp-reset
+
+    begin
+        welcome-main        sleep.1
+        clock-main          sleep.1
+        stars-main          sleep.1
+        invaders-main       sleep.1
+        s" looping" type cr
+    again
+
+    begin
+        haveip-handler
+    again
+;
+
+
+]module
+
+0 org
+
+code 0jump
+    \ h# 3e00 ubranch
+    main ubranch
+    main ubranch
+end-code
+
+meta
+
+hex
+
+: create-output-file w/o create-file throw to outfile ;
+
+\ .mem is a memory dump formatted for use with the Xilinx
+\ data2mem tool.
+s" j1.mem" create-output-file
+:noname
+    s" @ 20000" type cr
+    4000 0 do i t@ s>d <# # # # # #> type cr 2 +loop
+; execute
+
+\ .bin is a big-endian binary memory dump
+s" j1.bin" create-output-file
+:noname 4000 0 do i t@ dup 8 rshift emit emit 2 +loop ; execute
+
+\ .lst file is a human-readable disassembly 
+s" j1.lst" create-output-file
+d# 0
+h# 2000 disassemble-block

+ 14 - 0
j1/firmware/mkblob.py

@@ -0,0 +1,14 @@
+import Image
+import math
+
+im = Image.new("L", (32,32))
+radius = 16
+for i in range(32):
+  for j in range(32):
+    x = abs(i - 16)
+    y = abs(j - 16)
+    d = math.sqrt(x * x + y * y)
+    if d < radius:
+        t = 1.0 - (d / radius)
+        im.putpixel((i, j), int(255 * (t * t)))
+im.save("blob.png")

+ 36 - 0
j1/firmware/ntp.fs

@@ -0,0 +1,36 @@
+( NTP                                        JCB 09:54 11/17/10)
+
+: ntp-server 
+   \ h# 02830a00.
+   \ ip# 91.189.94.4 \ time.ubuntu
+   ip# 17.151.16.20  \ time.apple.com
+;
+
+: ntp-request
+    d# 123 d# 9999
+    ntp-server
+    net-my-ip
+    2over arp-lookup
+    ( dst-port src-port dst-ip src-ip *ethaddr )
+    udp-header
+    h# 2304 mac-pkt-, h# 04ec mac-pkt-, 
+    d# 6 mac-pkt-,0
+
+    d# 4 mac-pkt-,0 \ originate
+    d# 4 mac-pkt-,0 \ reference
+    d# 4 mac-pkt-,0 \ receive
+    \ d# 4 mac-pkt-,0 \ transmit
+    time@ mac-pkt-d, d# 2 mac-pkt-,0
+    udp-wrapup mac-send
+;
+
+: ntp-handler
+    IP_PROTO_UDP ip-isproto
+    ETH.IP.UDP.SOURCEPORT packet@ d# 123 = and
+    ETH.IP.UDP.DESTPORT packet@ d# 9999 = and
+    if
+        ETH.IP.UDP.NTP.TRANSMIT packetd@ setdate
+        time@ ETH.IP.UDP.NTP.ORIGINATE packetd@ d- setdelay
+    then
+;
+

+ 546 - 0
j1/firmware/nuc.fs

@@ -0,0 +1,546 @@
+( Nucleus: ANS Forth core and ext words      JCB 13:11 08/24/10)
+
+module[ nuc"
+
+32 constant sp
+0 constant false ( 6.2.1485 )
+: depth dsp h# ff and ;
+: true  ( 6.2.2298 ) d# -1 ;
+: 1+    d# 1 + ;
+: rot   >r swap r> swap ;
+: -rot  swap >r swap r> ;
+: 0=    d# 0 = ;
+: tuck  swap over ;
+: 2drop drop drop ;
+: ?dup  dup if dup then ;
+
+: split                     ( a m -- a&m a&~m )
+    over                    \ a m a
+    and                     \ a a&m
+    tuck                    \ a&m a a&m
+    xor                     \ a&m a&~m
+;
+
+: merge ( a b m -- m?b:a )
+    >r          \ a b
+    over xor    \ a a^b
+    r> and      \ a (a^b)&m
+    xor         \ ((a^b)&m)^a
+;
+
+: c@    dup @ swap d# 1 and if d# 8 rshift else d# 255 and then ;
+: c!    ( u c-addr )
+        swap h# ff and dup d# 8 lshift or swap
+        tuck dup @ swap         ( c-addr u v c-addr )
+        d# 1 and d# 0 = h# ff xor
+        merge swap !
+;
+: c!be d# 1 xor c! ;
+
+: looptest  ( -- FIN )
+    r>          ( xt )
+    r>          ( xt i )
+    1+
+    r@ over =   ( xt i FIN )
+    dup if
+        nip r> drop
+    else
+        swap >r
+    then        ( xt FIN )
+    swap
+    >r
+;
+
+\ Stack
+: 2dup  over over ;
+: +!    tuck @ + swap ! ;
+
+\ Comparisons
+: <>        = invert ;
+: 0<>       0= invert ;
+: 0<        d# 0 < ;
+: 0>=       0< invert ;
+: 0>        d# 0 ;fallthru
+: >         swap < ;
+: >=        < invert ;
+: <=        > invert ;
+: u>        swap u< ;
+
+\ Arithmetic
+: negate    invert 1+ ;
+: -         negate + ;
+: abs       dup 0< if negate then ;
+: min       2dup < ;fallthru
+: ?:        ( xt xf f -- xt | xf) if drop else nip then ;
+: max       2dup > ?: ;
+code cells end-code
+code addrcells end-code
+: 2*        d# 1 lshift ;
+code cell+ end-code
+code addrcell+ end-code
+: 2+        d# 2 + ;
+: 2-        1- 1- ;
+: 2/        d# 1 rshift ;
+: c+!       tuck c@ + swap c! ;
+
+: count     dup 1+ swap c@ ;
+: /string   dup >r - swap r> + swap ;
+: aligned   1+ h# fffe and ;
+
+: sliteral
+    r>
+    count
+    2dup 
+    +
+    aligned
+;fallthru
+: execute >r ;
+
+: 15down down1 ;fallthru
+: 14down down1 ;fallthru
+: 13down down1 ;fallthru
+: 12down down1 ;fallthru
+: 11down down1 ;fallthru
+: 10down down1 ;fallthru
+: 9down down1 ;fallthru
+: 8down down1 ;fallthru
+: 7down down1 ;fallthru
+: 6down down1 ;fallthru
+: 5down down1 ;fallthru
+: 4down down1 ;fallthru
+: 3down down1 ;fallthru
+: 2down down1 ;fallthru
+: 1down down1 ;fallthru
+: 0down copy ;
+
+: 15up up1     ;fallthru
+: 14up up1     ;fallthru
+: 13up up1     ;fallthru
+: 12up up1     ;fallthru
+: 11up up1     ;fallthru
+: 10up up1     ;fallthru
+: 9up up1     ;fallthru
+: 8up up1     ;fallthru
+: 7up up1     ;fallthru
+: 6up up1     ;fallthru
+: 5up up1     ;fallthru
+: 4up up1     ;fallthru
+: 3up up1     ;fallthru
+: 2up up1     ;fallthru
+: 1up up1     ;fallthru
+: 0up         ;
+
+code pickbody
+    copy    return
+    1down   scall   1up ubranch
+    2down   scall   2up ubranch
+    3down   scall   3up ubranch
+    4down   scall   4up ubranch
+    5down   scall   5up ubranch
+    6down   scall   6up ubranch
+    7down   scall   7up ubranch
+    8down   scall   8up ubranch
+    9down   scall   9up ubranch
+    10down  scall   10up ubranch
+    11down  scall   11up ubranch
+    12down  scall   12up ubranch
+    13down  scall   13up ubranch
+    14down  scall   14up ubranch
+    15down  scall   15up ubranch
+end-code
+
+: pick
+    dup 2* 2* ['] pickbody + execute ;
+
+: swapdown
+    ]asm
+        N     T->N              alu
+        T                   d-1 alu
+    asm[
+;
+: swapdowns
+    swapdown swapdown swapdown swapdown
+    swapdown swapdown swapdown swapdown
+    swapdown swapdown swapdown swapdown
+    swapdown swapdown swapdown swapdown ;fallthru
+: swapdown0 ;
+: roll
+    2*
+    ['] 0up over - >r
+    ['] swapdown0 swap - execute
+;
+
+\ ========================================================================
+\ Double
+\ ========================================================================
+
+: d=                        ( a b c d -- f )
+    >r                      \ a b c
+    rot xor                 \ b a^c
+    swap r> xor             \ a^c b^d
+    or 0=
+;
+
+: 2@                        ( ptr -- lo hi )
+    dup @ swap 2+ @
+;
+
+: 2!                        ( lo hi ptr -- )
+    rot over                \ hi ptr lo ptr
+    ! 2+ !
+;
+
+: 2over >r >r 2dup r> r> ;fallthru
+: 2swap rot >r rot r> ;
+: 2nip rot drop rot drop ;
+: 2rot ( d1 d2 d3 -- d2 d3 d1 ) 2>r 2swap 2r> 2swap ;
+: 2pick
+    2* 1+ dup 1+            \  lo hi ... 2k+1 2k+2
+    pick                    \  lo hi ... 2k+1 lo
+    swap                    \  lo hi ... lo 2k+1
+    pick                    \  lo hi ... lo hi
+;
+
+
+: d+                              ( augend . addend . -- sum . )
+    rot + >r                      ( augend addend)
+    over +                        ( augend sum)
+    dup rot                       ( sum sum augend)
+    u< if                         ( sum)
+        r> 1+
+    else
+        r>
+    then                          ( sum . )
+;
+
+: +h ( u1 u2 -- u1+u2/2**16 )
+    over +     ( a a+b )
+    u> d# 1 and
+;
+
+: +1c   \ one's complement add, as in TCP checksum
+    2dup +h + +
+;
+
+: s>d dup 0< ;
+: d1+ d# 1. d+ ;
+: dnegate
+    invert swap invert swap
+    d1+
+;
+: DABS ( d -- ud ) ( 8.6.1.1160 ) DUP 0< IF DNEGATE THEN ;
+
+: d- dnegate d+ ;
+
+\ Write zero to double
+: dz d# 0 dup rot 2! ;
+
+: dxor              \ ( a b c d -- e f )
+    rot xor         \ a c b^d
+    -rot xor        \ b^d a^c
+    swap
+;
+
+: dand      rot and -rot and swap ;
+: dor       rot or  -rot or  swap ;
+
+: dinvert  invert swap invert swap ;
+: d<            \ ( al ah bl bh -- flag )
+    rot         \ al bl bh ah
+    2dup =
+    if
+        2drop u<
+    else
+        2nip >
+    then
+;
+
+: d> 2swap d< ;
+: d0<= d# 0. ;fallthru
+: d<= d> invert ;
+: d>= d< invert ;
+: d0= or 0= ;
+: d0< d# 0. d< ;
+: d0<> d0= invert ;
+: d<> d= invert ;
+: d2* 2dup d+ ;
+: d2/ dup d# 15 lshift >r 2/ swap 2/ r> or swap ;
+: dmax       2over 2over d< if 2swap then 2drop ;
+
+: d1- d# -1. d+ ;
+
+: d+!                   ( v. addr -- )
+    dup >r
+    2@
+    d+
+    r>
+    2!
+;
+
+: move ( addr1 addr2 u -- )
+    d# 0 do
+        over @ over !
+        2+ swap 2+ swap
+    loop
+    2drop
+;
+
+: cmove ( c-addr1 c-addr2 u -- )
+    d# 0 do
+        over c@ over c!
+        1+ swap 1+ swap
+    loop
+    2drop
+;
+
+: bounds ( a n -- a+n a ) OVER + SWAP ;
+: fill ( c-addr u char -- ) ( 6.1.1540 )
+  >R  bounds
+  BEGIN 2dupxor
+  WHILE R@ OVER C! 1+
+  REPEAT R> DROP 2DROP ;
+
+\ Math
+
+0 [IF]
+create scratch d# 2 allot
+: um*  ( u1 u2 -- ud )
+    scratch !
+    d# 0.
+    d# 16 0do
+        2dup d+
+        rot dup 0< if
+            2* -rot
+            scratch @ d# 0 d+
+        else
+            2* -rot
+        then
+    loop
+    rot drop
+;
+[ELSE]
+: um*   mult_a ! mult_b ! mult_p 2@ ;
+[THEN]
+
+: *         um* drop ;
+: abssgn    ( a b -- |a| |b| negf )
+        2dup xor 0< >r abs swap abs swap r> ;
+
+: m*    abssgn >r um* r> if dnegate then ;
+
+: divstep
+    ( divisor dq hi )
+    2*
+    over 0< if 1+ then
+    swap 2* swap
+    rot                     ( dq hi divisor )
+    2dup >= if
+        tuck                ( dq divisor hi divisor )
+        -
+        swap                ( dq hi divisor )
+        rot 1+              ( hi divisor dq )
+        rot                 ( divisor dq hi )
+    else
+        -rot
+    then
+    ;
+
+: um/mod ( ud u1 -- u2 u3 ) ( 6.1.2370 )
+    -rot 
+    divstep divstep divstep divstep
+    divstep divstep divstep divstep
+    divstep divstep divstep divstep
+    divstep divstep divstep divstep
+    rot drop swap
+;
+
+: /mod  >R S>D R> ;fallthru
+: SM/REM ( d n -- r q ) ( 6.1.2214 ) ( symmetric )
+  OVER >R >R  DABS R@ ABS UM/MOD
+  R> R@ XOR 0< IF NEGATE THEN  R> 0< IF >R NEGATE R> THEN ;
+: /     /mod nip ;
+: mod   /mod drop ;
+: */mod >R M* R> SM/REM ;
+: */    */mod nip ;
+
+: t2* over >r >r d2*
+    r> 2* r> 0< d# 1 and + ;
+
+variable divisor
+: m*/mod
+    divisor !
+    tuck um* 2swap um*   ( hi. lo. )
+                         ( m0 h l m1 )
+    swap >r d# 0 d+ r>   ( m h l )
+    -rot                 ( l m h )
+    d# 32 0do
+        t2*
+        dup divisor @ >= if
+            divisor @ -
+            rot 1+ -rot
+        then
+   loop
+;
+: m*/ m*/mod drop ;
+
+
+\ Numeric output - from eforth
+
+variable base
+variable hld
+create pad 84 allot create pad|
+
+: <# ( -- ) ( 6.1.0490 )( h# 96 ) pad| HLD ! ;
+: DIGIT ( u -- c ) d# 9 OVER < d# 7 AND + [CHAR] 0 + ;
+: HOLD ( c -- ) ( 6.1.1670 ) HLD @ 1- DUP HLD ! C! ;
+
+: # ( d -- d ) ( 6.1.0030 )
+  d# 0 BASE @ UM/MOD >R BASE @ UM/MOD SWAP DIGIT HOLD R> ;
+
+: #S ( d -- d ) ( 6.1.0050 ) BEGIN # 2DUP OR 0= UNTIL ;
+: #> ( d -- a u ) ( 6.1.0040 ) 2DROP HLD @ pad| OVER - ;
+
+: SIGN ( n -- ) ( 6.1.2210 ) 0< IF [CHAR] - HOLD THEN ;
+
+\ hex(int((1<<24) * (115200 / 2400.) / (WB_CLOCK_FREQ / 2400.)))
+\ d# 42000000 constant WB_CLOCK_FREQ
+
+[ 48000000 17 12 */ ] constant WB_CLOCK_FREQ
+
+0 [IF]
+: uartbase
+    [ $100000000. 115200 WB_CLOCK_FREQ m*/ drop $ffffff00 and dup swap 16 rshift ] 2literal
+;
+: emit-uart
+    begin uart_0 @ 0= until
+    s>d
+    uartbase dor
+    uart_1 ! uart_0 !
+;
+[ELSE]
+: emit-uart drop ;
+[THEN]
+
+create 'emit
+meta emit-uart t, target
+
+: emit 'emit @ execute ;
+: cr d# 13 emit d# 10 emit ;
+d# 32 constant bl
+: space bl emit ;
+: spaces    begin dup 0> while space 1- repeat drop ;
+
+: hex1 d# 15 and dup d# 10 < if d# 48 else d# 55 then + emit ;
+: hex2
+    dup 
+    d# 4 rshift
+    hex1 hex1
+;
+: hex4
+    dup
+    d# 8 rshift
+    hex2 hex2 ;
+
+: hex8 hex4 hex4 ;
+
+: type
+    d# 0 do
+        dup c@ emit
+        1+
+    loop
+    drop
+;
+
+: dump
+    ( addr u )
+    0do
+        dup d# 15 and 0= if dup cr hex4 [char] : emit space space then
+        dup c@ hex2 space 1+
+    loop
+    cr drop
+;
+
+: dump16
+    ( addr u )
+    0do
+        dup hex4 [char] : emit space dup @ hex4 cr 2+
+    loop
+    drop
+;
+
+: decimal d# 10 base ! ;
+: hex d# 16 base ! ;
+
+: S.R ( a u n -- ) OVER - SPACES TYPE ;
+: D.R ( d n -- ) ( 8.6.1.1070 ) >R DUP >R DABS <# #S R> SIGN #> R> S.R ;
+: U.R ( u n -- ) ( 6.2.2330 ) d# 0 SWAP D.R ;
+: .R ( n n -- ) ( 6.2.0210 ) >R S>D R> D.R ;
+
+: D. ( d -- ) ( 8.6.1.1060 ) d# 0 D.R SPACE ;
+: U. ( u -- ) ( 6.1.2320 ) d# 0 D. ;
+: . ( n -- ) ( 6.1.0180 ) BASE @ d# 10 XOR IF U. EXIT THEN S>D D. ;
+: ? ( a -- ) ( 15.6.1.0600 ) @ . ;
+
+( Numeric input )
+
+: DIGIT? ( c base -- u f ) ( 0xA3 )
+  >R [CHAR] 0 - D# 9 OVER <
+  IF D# 7 - DUP D# 10 < OR THEN DUP R> U< ;
+
+: >number ( ud a u -- ud a u ) ( 6.1.0570 )
+    begin
+        dup 0= if exit then
+        over c@ base @ digit? if
+            >r 2swap
+            drop base @ um*
+            r> s>d d+ 2swap
+            d# 1 /string >number
+        else
+            drop exit
+        then
+    again
+;
+
+: .s
+    [char] < emit
+    depth dup hex2
+    [char] > emit
+
+    d# 8 min
+    ?dup if
+        0do
+            i pick hex4 space
+        loop
+    then
+;
+
+build-debug? [IF]
+: (assert)
+    s" **** ASSERTION FAILED **** " type
+    ;fallthru
+: (snap)
+    type space
+    s" LINE " type
+    .
+    [char] : emit
+    space
+    .s
+    cr
+;
+[THEN]
+
+\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+: endian dup d# 8 lshift swap d# 8 rshift or ;
+: 2endian endian swap endian ;
+: swab endian ;
+: typepad ( c-addr u w )    over - >r type r> spaces ;
+: even?     d# 1 and 0= ;
+
+\ rise? and fall? act like ! - except that they leave a true
+\ if the value rose or fell, respectively.
+
+: rise?   ( u a -- f ) 2dup @ u> >r ! r> ;
+: fall?   ( u a -- f ) 2dup @ u< >r ! r> ;
+
+]module

+ 11 - 0
j1/firmware/packet.fs

@@ -0,0 +1,11 @@
+( Packet construction, tx, rx                JCB 13:25 08/24/10)
+module[ packet"
+
+: packet@ ( u -- u )
+    mac-inoffset mac@ ;
+
+: packetd@ ( u -- ud )
+    mac-inoffset dup 2+ mac@ swap mac@ ;
+
+
+]module

+ 434 - 0
j1/firmware/ps2kb.fs

@@ -0,0 +1,434 @@
+( PS/2 keyboard handler                      JCB 18:29 11/21/10)
+
+================================================================
+
+Keycodes represent raw keypresses.  Need to map these to
+ASCII characters.  Each key can generate several ASCII
+codes depending on the state of the SHIFT/CTRL keys.
+
+Could use table giving keycode->ascii, but most keys
+generate two codes, so would need word for each.
+Keycodes 00-83.  Storage 262 bytes.
+
+Table of N ascii codes, each entry specifies a keycode
+and shift state
+
+================================================================
+
+module[ ps2kb"
+
+meta
+
+create asciikb 144 allot
+asciikb 144 erase
+
+\ 1 word for each key.
+\ if high bit is zero, then 
+
+h# 84 constant nscancodes
+create scanmap nscancodes cells allot
+scanmap nscancodes cells 2constant scanmap_
+scanmap_ erase
+
+: scanmap! ( n u -- ) \ write n to cell u in scanmap
+    cells scanmap + !
+;
+
+\ knowkey   plain xx                            f0xx
+\ knowkey-n plain 3x, yy numlock                exyy
+\ knowkey-h shift mask yy                       d0yy
+\ knowkey-s plain xx, shifted^caps yy           xxyy
+
+h# f000 constant plainmask
+h# e000 constant numlockmask
+h# d000 constant shiftmask
+
+: wordval   bl word count evaluate ;
+
+: knowkey
+    wordval
+    plainmask or
+    swap scanmap!
+;
+: knowkey-s
+    \ dup char asciikb + c!
+    \ 128 or
+    \ char asciikb + c!
+    char 8 lshift char or
+    swap scanmap!
+;
+: knowkey-h
+    wordval shiftmask or
+    swap scanmap!
+;
+: knowkey-n
+    \ dup char asciikb + c!
+    \ 128 or
+    \ char asciikb + c!
+    char [char] . - 8 lshift wordval or
+    numlockmask or
+    swap scanmap!
+;
+
+h# 01 constant SHIFTL
+h# 02 constant SHIFTR
+h# 04 constant CONTROL
+h# 08 constant ALT
+char * constant ASTERISK
+char - constant MINUS
+char + constant PLUS
+char 5 constant FIVE
+
+include keycodes.fs
+
+h# 76 knowkey ESC
+h# 05 knowkey KF1
+h# 06 knowkey KF2
+h# 04 knowkey KF3
+h# 0c knowkey KF4
+h# 03 knowkey KF5
+h# 0b knowkey KF6
+h# 83 knowkey KF7
+h# 0a knowkey KF8
+h# 01 knowkey KF9
+h# 09 knowkey KF10
+h# 78 knowkey KF11
+h# 07 knowkey KF12
+
+h# 0e knowkey-s ` ~ 
+h# 16 knowkey-s 1 ! 
+h# 1e knowkey-s 2 @ 
+h# 26 knowkey-s 3 # 
+h# 25 knowkey-s 4 $ 
+h# 2e knowkey-s 5 % 
+h# 36 knowkey-s 6 ^ 
+h# 3d knowkey-s 7 & 
+h# 3e knowkey-s 8 * 
+h# 46 knowkey-s 9 ( 
+h# 45 knowkey-s 0 ) 
+h# 4e knowkey-s - _ 
+h# 55 knowkey-s = + 
+h# 5d knowkey-s \ | 
+h# 66 knowkey KDEL
+
+h# 0d knowkey TAB
+h# 15 knowkey-s q Q
+h# 1d knowkey-s w W
+h# 24 knowkey-s e E
+h# 2d knowkey-s r R
+h# 2c knowkey-s t T
+h# 35 knowkey-s y Y
+h# 3c knowkey-s u U
+h# 43 knowkey-s i I
+h# 44 knowkey-s o O
+h# 4d knowkey-s p P
+h# 54 knowkey-s [ {
+h# 5b knowkey-s ] }
+h# 5a knowkey ENTER
+
+h# 58 knowkey -1
+h# 1c knowkey-s a A
+h# 1b knowkey-s s S
+h# 23 knowkey-s d D
+h# 2b knowkey-s f F
+h# 34 knowkey-s g G
+h# 33 knowkey-s h H
+h# 3b knowkey-s j J
+h# 42 knowkey-s k K
+h# 4b knowkey-s l L
+h# 4c knowkey-s ; :
+h# 52 knowkey-s ' "
+
+h# 1a knowkey-s z Z
+h# 22 knowkey-s x X
+h# 21 knowkey-s c C
+h# 2a knowkey-s v V
+h# 32 knowkey-s b B
+h# 31 knowkey-s n N
+h# 3a knowkey-s m M
+h# 41 knowkey-s , <
+h# 49 knowkey-s . >
+h# 4a knowkey-s / ?
+
+h# 29 knowkey BL
+
+h# 12 knowkey-h SHIFTL
+h# 59 knowkey-h SHIFTR
+h# 14 knowkey-h CONTROL
+h# 11 knowkey-h ALT
+
+h# 70 knowkey-n 0 KINS
+h# 71 knowkey-n . KDEL
+h# 69 knowkey-n 1 KEND
+h# 72 knowkey-n 2 KDOWN
+h# 7a knowkey-n 3 KPGDN
+h# 6b knowkey-n 4 KLEFT
+h# 73 knowkey     FIVE 
+h# 74 knowkey-n 6 KRIGHT
+h# 6c knowkey-n 7 KHOME
+h# 75 knowkey-n 8 KUP
+h# 7d knowkey-n 9 KPGUP
+h# 77 knowkey -2
+h# 7c knowkey     ASTERISK
+h# 7b knowkey     MINUS
+h# 79 knowkey     PLUS
+
+: t,c ( c-addr u -- ) \ compile u cells into target memory
+    0 do
+        dup @ t, cell+
+    loop
+    drop
+;
+
+target create scanmap meta
+scanmap nscancodes t,c
+
+target
+
+include keycodes.fs
+
+: scanmap@ ( u - u ) \ return scanmap entry u
+    cells scanmap + @ ;
+
+variable kbread         \ read ptr into 64-bit KB fifo
+variable kbstate        \ accumulates 11-bit code
+
+: ps2listening
+    ps2_clk_dir in
+    ps2_dat_dir in
+;
+: kbfifo@ ( u -- f )    \ read bit u from 64-bit KB fifo
+    dup d# 4 rshift 2* kbfifo + @
+    swap d# 15 and rshift d# 1 and
+;
+: kbnew ( -- ) \ start accumulating new code
+    h# 800 kbstate !
+;
+: kbfifo-cold
+    kbfifocount @ kbread !
+    kbnew
+;
+: kbfifo-fullness ( -- u ) \ how many unread bits in the kbfifo
+    kbfifocount @ kbread @ - h# ff and
+;
+
+variable ps2_clk'
+: waitfall \ wait for falling edge on ps2_clk
+    begin ps2_clk @ ps2_clk' fall? until ;
+
+: ps2-out1 ( u -- ) \ send lsb of u to keyboard
+    ps2_dat ! waitfall ;
+
+: oddparity ( u1 -- u2 ) \ u2 is odd parity of u1
+    dup d# 4 rshift xor
+    dup d# 2 rshift xor
+    dup 2/ xor
+;
+
+: kb-request
+    ps2_clk_dir out ps2_clk off \ clock low
+    d# 60. sleepus
+    ps2_dat_dir out ps2_dat off \ dat low
+    ps2_clk_dir in              \ release clock
+
+    begin ps2_clk @ until
+    ps2_clk' on
+
+    \ bad keyboard hangs here
+    false ps2-out1              \ start
+
+    dup 
+    d# 8 0do
+        dup ps2-out1 2/
+    loop
+    drop
+
+    oddparity ps2-out1          \ parity
+    true ps2-out1               \ stop
+
+    ps2listening \ waitfall
+    kbfifo-cold
+;
+
+: kbbit
+    d# 11 lshift kbstate @ 2/ or
+    kbstate !
+;
+: rawready? ( -- f) \ is the raw keycode ready?
+    kbstate @ d# 1 and ;
+
+: kbraw ( -- u ) \ get the current raw keycode
+    kbstate @ d# 2 rshift h# ff and
+    kbnew
+;
+
+variable lock
+
+: rawloop
+    begin
+        kbfifocount @ lock !
+        kbfifo-fullness 0<>
+        rawready? 0= and
+    while
+        kbfifo-fullness 1- kbfifo@
+        kbfifocount @ lock @ = if
+            kbbit d# 1 kbread +!
+        else
+            drop
+        then
+    repeat
+;
+
+: oneraw
+    begin
+        rawloop
+        rawready?
+    until
+    kbraw
+;
+
+: >leds ( u -- ) \ set keyboard leds (CAPS NUM SCROLL)
+    h# ed kb-request
+    oneraw drop
+    kb-request
+;
+
+( Decoding                                   JCB 19:25 12/04/10)
+
+variable capslock
+variable numlock
+variable isrelease  \ is this is key release
+variable ise0       \ is this an E0-prefix key
+0 value mods        \ bitmask of modifier keys
+                    \ RALT RCTRL -- -- LALT LCTRL RSHIFT LSHIFT
+
+: lrshift? ( -- f ) \ is either shift pressed?
+    mods h# 03 and ;
+: lrcontrol?
+    mods h# 44 and ;
+: lralt?
+    mods h# 88 and ;
+
+variable curkey
+
+: append ( u -- ) \ join u with mods write to curkey
+    h# ff and mods d# 8 lshift or
+    curkey !
+;
+
+: shiftmask
+    h# ff and
+    ise0 @ if d# 4 lshift then
+;
+: shift-press ( u -- ) \ a shift key was pressed
+    shiftmask mods or to mods ;
+: shift-release ( u -- ) \ a shift key was released
+    shiftmask invert mods and to mods ;
+
+: shiftable-press ( u -- ) \ a shiftable key was pressed
+    mods d# 3 and 0= capslock @ xor if
+        d# 8 rshift
+    then
+    append
+;
+: ignore drop ;
+
+: myleds \ compute led values from caps/numlock, send to KB
+    numlock @ d# 2 and
+    capslock @ d# 4 and
+    or
+    >leds 
+;
+
+: toggle ( a -- ) \ invert cell at a
+    dup @ invert swap ! ;
+
+: plain-press ( u -- )
+    dup d# -1 = if
+        drop capslock toggle myleds
+    else
+        dup d# -2 = if
+            drop numlock toggle myleds
+        else
+            append
+        then
+    then
+;
+
+: num-press
+    \ if e0 prefix, low code, else hi code or 30
+    \ e0  numlock
+    \ 0   0         cursor
+    \ 0   1         num
+    \ 1   0         cursor
+    \ 1   1         cursor
+    ise0 @ 0= numlock @ and if
+        d# 8 rshift h# f and [char] . +
+    then
+    append
+;
+
+jumptable keyhandler
+\          PRESS                RELEASE
+( 0 )    | shiftable-press      | ignore
+( d )    | shift-press          | shift-release
+( e )    | num-press            | ignore
+( f )    | plain-press          | ignore
+
+: handle-raw ( u -- )
+    dup h# e0 = if
+        drop ise0 on
+    else
+        dup h# f0 = if
+            drop isrelease on
+        else
+            dup h# 84 < if
+                scanmap@
+                \ hi 4 bits,
+                \     1100 -> 0
+                \     1101 -> 1
+                \     1110 -> 2
+                \     1111 -> 3
+                \
+                dup d# 12 rshift d# 12 - d# 0 max
+
+                2* isrelease @ + keyhandler execute
+
+                isrelease off
+                ise0 off
+            else
+                drop
+            then
+        then
+    then
+;
+
+( kb: high-level keyboard                    JCB 19:45 12/04/10)
+
+: kb-cold
+    ps2listening kbfifo-cold
+    h# 7 >leds
+    sleep.1
+    h# 0 >leds
+
+    numlock off
+    capslock off
+    curkey off
+;
+
+: kbfifo-proc
+    rawloop
+    rawready? if
+        kbraw handle-raw
+    then
+;
+
+: key?  ( -- flag )
+    kbfifo-proc
+    curkey @ 0<> ;
+: key   ( -- u )
+    begin key? until
+    curkey @ curkey off ;
+
+]module
+

+ 36 - 0
j1/firmware/sincos.fs

@@ -0,0 +1,36 @@
+( Sine and cosine                            JCB 18:29 11/18/10)
+
+create sintab
+
+meta
+
+: mksin
+    65 0 do
+        i s>d d>f 128e0 f/ pi f* fsin
+        32767e0 f* f>d drop
+        t,
+    loop
+;
+mksin
+
+target
+
+: sin ( th -- v )
+    dup d# 128 and >r
+    d# 127 and
+    dup d# 63 > if
+        invert d# 129 + \ 64->64, 65->63
+    then
+    cells sintab + @
+    r> if
+        negate
+    then
+;
+
+: cos d# 64 + sin ;
+
+: sin* ( s th -- sinth * s )
+    sin swap 2* m* nip ;
+
+: cos* ( s th -- costh * s )
+    cos swap 2* m* nip ;

+ 20 - 0
j1/firmware/sprite.fs

@@ -0,0 +1,20 @@
+( Sprite low-level                           JCB 15:23 11/15/10)
+
+: vga-line@
+    begin
+        vga_line @
+        vga_line @
+        over xor
+    while
+        drop
+    repeat
+;
+
+: waitblank begin vga-line@ d# 512 = until ;
+
+: sprite! ( x y spr -- )
+    2* cells vga_spritey + tuck ! 2- ! ;
+
+: hide  \ hide all the sprites at (800,800)
+    d# 8 0do d# 800 dup i sprite! loop ;
+

+ 67 - 0
j1/firmware/tftp.fs

@@ -0,0 +1,67 @@
+( TFTP                                       JCB 09:16 11/11/10)
+
+variable blocknum
+
+: tftp-ack ( -- )
+    d# 2 ETH.IP.SRCIP mac-inoffset mac@n arp-lookup if
+        ETH.IP.UDP.SOURCEPORT packet@ 
+        d# 1077
+        d# 2 ETH.IP.SRCIP mac-inoffset mac@n  
+        net-my-ip
+        2over arp-lookup
+        ( dst-port src-port dst-ip src-ip *ethaddr )
+        udp-header
+        d# 4 mac-pkt-,
+        blocknum @ mac-pkt-,
+        udp-wrapup mac-send
+    then
+;
+
+: tftp-handler ( -- )
+    IP_PROTO_UDP ip-isproto if
+        OFFSET_UDP_DESTPORT packet@ d# 69 = if
+            udp-checksum? if
+                ETH.IP.UDP.TFTP.OPCODE packet@ 
+                s" tftp opcode=" type dup hex4 cr
+                dup d# 2 = if
+                    s" WRQ filename: " type
+                    ETH.IP.UDP.TFTP.RWRQ.FILENAME mac-inoffset d# 32 mac-dump
+
+                    d# 0 blocknum !
+                    tftp-ack
+                then
+                drop
+            then
+        then
+        OFFSET_UDP_DESTPORT packet@ d# 1077 = if
+            udp-checksum? if
+                ETH.IP.UDP.TFTP.OPCODE packet@ 
+                s" tftp opcode=" type dup hex4 cr
+                dup d# 3 = if
+                    s" tftp recv=" type ETH.IP.UDP.TFTP.DATA.BLOCK packet@ hex4 s"  expected=" type blocknum @ 1+ hex4 cr
+                    blocknum @ 1+
+                    ETH.IP.UDP.TFTP.DATA.BLOCK packet@ = if
+                        \ data at ETH.IP.UDP.TFTP.DATA.DATA
+                        ETH.IP.UDP.TFTP.DATA.DATA mac-inoffset
+                        blocknum @ d# 9 lshift h# 2000 +
+                        d# 256 0do
+                            over mac@ h# 5555 xor over h# 3ffe min !
+                            2+ swap 2+ swap
+                        loop
+                        2drop
+                        d# 1 blocknum +!
+                        tftp-ack
+                        ETH.IP.UDP.LENGTH packet@ d# 12 - 0= if
+                            h# 2000 h# 100 dump
+                            bootloader
+                        then
+                    else
+                        s" unexpected blocknum" type cr
+                        tftp-ack
+                    then
+                then
+                drop
+            then
+        then
+    then
+;

+ 33 - 0
j1/firmware/time.fs

@@ -0,0 +1,33 @@
+( Time access                                JCB 13:27 08/24/10)
+
+variable prevth     \ previous high time
+2variable timeh     \ high 32 bits of time
+
+: time@  ( -- time. )
+    begin
+        time 2@
+        time 2@
+        2over d<>
+    while
+        2drop
+    repeat
+
+\   dup prevth fall? if
+\       d# 1. timeh d+!
+\   then
+;
+
+: timeq     ( -- d d ) \ 64-bit time
+    time@ timeh 2@ ;
+
+: setalarm ( d a -- ) \ set alarm a for d microseconds hence
+    >r time@ d+ r> 2! ;
+: isalarm ( a -- f )
+    2@ time@ d- d0<= ;
+
+2variable sleeper
+: sleepus   sleeper setalarm begin sleeper isalarm until ;
+: sleep.1   d# 100000. sleepus ;
+: sleep1    d# 1000000. sleepus ;
+
+: took ( d -- ) time@ 2swap d- s" took " type d. cr ;

+ 311 - 0
j1/firmware/twist.py

@@ -0,0 +1,311 @@
+from twisted.internet.protocol import DatagramProtocol
+from twisted.internet import reactor, task
+from twisted.internet.task import deferLater
+
+import os
+import time
+import struct
+import sys
+import hashlib
+import operator
+import functools
+import random
+
+class Transporter(DatagramProtocol):
+
+    def __init__(self, jobs):
+        self.udp_transport = reactor.listenUDP(9947, self)
+        self.pending = {}
+        self.seq = 0
+        self.jobs = jobs
+        self.firstjob()
+        task.LoopingCall(self.earliest).start(0.1)
+        reactor.run()
+
+    def firstjob(self):
+        self.jobs[0].startwork(self)
+
+    def propose(self, cmd, rest):
+        seq = self.seq
+        self.seq += 1
+        data = struct.pack(">HH", seq, cmd) + rest;
+        self.pending[seq] = (time.time(), data)
+        return seq
+
+    def earliest(self):
+        bytime = [(t, k) for (k, (t, _)) in self.pending.items()]
+        for (t, seq) in sorted(bytime)[:32]:
+            self.send(seq)
+            self.pending[seq] = (time.time(), self.pending[seq][1])
+
+    def datagramReceived(self, data, (host, port)):
+        # print "received %r from %s:%d" % (data, host, port)
+        (opcode, seq) = struct.unpack(">HH", data[:4])
+        assert opcode == 0
+        if seq in self.pending:
+            del self.pending[seq]
+            try:
+                self.jobs[0].addresult(self, seq, data[4:])
+            except AssertionError as e:
+                print 'assertion failed', e
+                reactor.stop()
+                return
+            print "ACK ", seq, "pending", len(self.pending)
+            if len(self.pending) == 0:
+                self.jobs[0].close()
+                self.jobs = self.jobs[1:]
+                if self.jobs != []:
+                    self.firstjob()
+                else:
+                    reactor.stop()
+            # self.transport.write(data, (host, port))
+
+    def send(self, seq):
+        (_, data) = self.pending[seq]
+        # print "send %r" % data
+        self.udp_transport.write(data, ("192.168.0.99", 947))
+
+    def addresult(self, seq, payload):
+        pass
+
+
+class Action(object):
+    def addresult(self, tr, seq, payload):
+        pass
+
+    def close(self):
+        pass
+
+class ReadRAM(Action):
+
+    def startwork(self, tr):
+        self.result = 16384 * [None]
+        self.seqs = {}
+        for i in range(0, 128):
+            self.seqs[tr.propose(0, struct.pack(">H", i * 128))] = i * 128
+
+    def addresult(self, tr, seq, payload):
+        addr = self.seqs[seq]
+        assert len(payload) == 128
+        for i in range(128):
+            self.result[addr + i] = ord(payload[i])
+
+    def close(self):
+        for a in range(0, 16384, 16):
+            print ("%04x  " % a) + " ".join("%02x" % x for x in self.result[a:a+16])
+
+
+class WriteRAM(Action):
+
+    def startwork(self, tr):
+        code = open('j1.bin').read()
+        for i in range(0x1f80 / 128):
+            print i
+            o = 128 * i
+            tr.propose(1, struct.pack(">H128s", 0x2000 + o, code[o:o+128]))
+
+class VerifyRAM(ReadRAM):
+    def close(self):
+        actual = "".join([chr(c) for c in self.result[0x2000:]])
+        expected = open('j1.bin').read()
+        l = 0x1f80
+        assert actual[:l] == expected[:l]
+
+class Reboot(Action):
+    def startwork(self, tr):
+        tr.propose(2, "")
+
+class ReadFlash(Action):
+
+    def startwork(self, tr):
+        self.result = 2 * 1024 * 1024 * [None]
+        self.seqs = {}
+        for addr in range(0, len(self.result), 128):
+            self.seqs[tr.propose(3, struct.pack(">I", addr))] = addr
+
+    def addresult(self, tr, seq, payload):
+        addr = self.seqs[seq]
+        assert len(payload) == 128
+        for i in range(128):
+            self.result[addr + i] = ord(payload[i])
+
+    def close(self):
+        open('flash.dump', 'w').write("".join([chr(x) for x in self.result]))
+        for a in range(0, 256, 16):
+            print ("%04x  " % a) + " ".join("%02x" % x for x in self.result[a:a+16])
+
+class EraseFlash(Action):
+    def startwork(self, tr):
+        tr.propose(4, "")
+    def close(self):
+        time.sleep(5)
+
+class WaitFlash(Action):
+    def startwork(self, tr):
+        self.seq = tr.propose(5, struct.pack(">I", 0))
+    def addresult(self, tr, seq, payload):
+        (res,) = struct.unpack(">H", payload)
+        if res == 0:
+            self.startwork(tr)
+
+def bitload(bitfilename):
+    bit = open(bitfilename, "r")
+
+    def getH(fi):
+        return struct.unpack(">H", bit.read(2))[0]
+    def getI(fi):
+        return struct.unpack(">I", bit.read(4))[0]
+
+    bit.seek(getH(bit), os.SEEK_CUR)
+    assert getH(bit) == 1
+
+    # Search for the data section in the .bit file...
+    while True:
+        ty = ord(bit.read(1))
+        if ty == 0x65:
+            break
+        length = getH(bit)
+        bit.seek(length, os.SEEK_CUR)
+    fieldLength = getI(bit)
+    return bit.read(fieldLength)
+
+# open("xxx", "w").write(bitload("j1_program.bit"))
+
+import intelhex
+import array
+
+class Hexfile(object):
+    def __init__(self, filename):
+        self.hf = intelhex.IntelHex(filename)
+        self.hf.readfile()
+        while (self.hf.maxaddr() % 128) != 127:
+            self.hf[self.hf.maxaddr() + 1] = 0xff
+        print "%x %x" % (self.hf.minaddr(), self.hf.maxaddr())
+
+    def minmax(self):
+        return (self.hf.minaddr(), self.hf.maxaddr())
+
+    # The XESS CPLD bootloader runs the flash in byte mode,
+    # and the flash is littleendian, so must do the endian
+    # swap here
+    def blk(self, o):
+        b128 = array.array('B', [self.hf[o + i] for i in range(128)]).tostring()
+        hh = array.array('H', b128)
+        hh.byteswap()
+        return hh.tostring()
+
+class WriteFlash(Action, Hexfile):
+
+    def startwork(self, tr):
+        for o in range(self.hf.minaddr(), self.hf.maxaddr(), 128):
+            tr.propose(6, struct.pack(">I", o) + self.blk(o))
+
+class VerifyFlash(Action, Hexfile):
+
+    def startwork(self, tr):
+        self.seqs = {}
+        for o in range(self.hf.minaddr(), self.hf.maxaddr(), 128):
+            self.seqs[tr.propose(3, struct.pack(">I", o))] = o
+
+    def addresult(self, tr, seq, payload):
+        addr = self.seqs[seq]
+        assert len(payload) == 128, 'short packet'
+        assert self.blk(addr) == payload, "mismatch at %#x" % addr
+
+    def close(self):
+        print "Flash verified OK"
+
+class EraseSector(Action):
+    def __init__(self, a):
+        self.a = a
+    def startwork(self, tr):
+        tr.propose(7, struct.pack(">I", self.a))
+    def close(self):
+        time.sleep(.1)
+
+class WaitSector(Action):
+    def __init__(self, a):
+        self.a = a
+    def startwork(self, tr):
+        self.seq = tr.propose(5, struct.pack(">I", self.a))
+    def addresult(self, tr, seq, payload):
+        (res,) = struct.unpack(">H", payload)
+        if res == 0:
+            self.startwork(tr)
+
+class LoadSector(Action):
+    def __init__(self, a, data):
+        self.a = a
+        self.data = data
+    def startwork(self, tr):
+        for o in range(0, len(self.data), 128):
+            blk = self.data[o:o+128]
+            if blk != (128 * chr(0xff)):
+                tr.propose(6, struct.pack(">I", self.a + o) + blk)
+
+class DumpSector(Action):
+
+    def __init__(self, a):
+        self.a = a
+    def startwork(self, tr):
+        self.seqs = {}
+        for o in [0]:
+            self.seqs[tr.propose(3, struct.pack(">I", self.a + o))] = o
+
+    def addresult(self, tr, seq, payload):
+        addr = self.a + self.seqs[seq]
+        assert len(payload) == 128
+        print "result", repr(payload)
+
+# t = Transporter([WriteRAM(), VerifyRAM(), Reboot()])
+# t = Transporter([EraseFlash(), WaitFlash()])
+# sys.exit(0)
+
+erasing = [EraseFlash(), WaitFlash()]
+bases = [ 0 ]
+bases = [0, 0x80000, 0x100000, 0x180000]
+bases = [0x80000]
+# Transporter(erasing + [WriteFlash("j1_program_%x.mcs" % base) for base in bases])
+# Transporter([VerifyFlash("j1_program_%x.mcs" % base) for base in bases])
+# Transporter([EraseSector(seca), WaitSector(seca), ld, DumpSector(seca)])
+
+def loadcode(dsta, filenames):
+    data = "".join([open(fn).read() for fn in filenames])
+    return [EraseSector(dsta),
+            WaitSector(dsta),
+            LoadSector(dsta, data)]
+
+def pngstr(filename):
+    import Image
+    sa = array.array('B', Image.open(filename).convert("L").tostring())
+    return struct.pack('>1024H', *sa.tolist())
+
+def erasesecs(lo, hi):
+    r = []
+    for s in range(lo, hi, 65536):
+        r += [EraseSector(s), WaitSector(s)]
+    return r
+
+def loadhex(filename):
+    w = WriteFlash(filename)
+    (lo, hi) = w.minmax()
+    return erasesecs(lo, hi) + [w]
+
+def loadsprites(dsta, filenames):
+    data = "".join([pngstr(f) for f in filenames])
+    print "Loading %d bytes" % len(data)
+    return erasesecs(dsta, dsta + len(data)) + [LoadSector(dsta, data)]
+
+# Transporter(loadcode(0x180000, ["j1.png.pic", "font8x8", "j1.png.chr"]) + [Reboot()])
+spr = ["%d.png" % (i/2) for i in range(16)]
+spr += ["blob.png"] * 16
+spr += ["fsm-32.png", "pop.png"] * 6 + ["bomb.png", "pop.png", "shot.png", "pop.png"]
+              
+# Transporter(loadsprites(0x200000, spr))
+# Transporter(loadcode(0x190000, ["j1.bin"]) + [Reboot()])
+# t = Transporter([ReadFlash()])
+
+Transporter(
+# loadhex("j1_program_80000.mcs")
+loadcode(0x190000, ["j1.bin"]) + [Reboot()]
+)

+ 41 - 0
j1/firmware/udp.fs

@@ -0,0 +1,41 @@
+( UDP header and wrapup                      JCB 13:22 08/24/10)
+
+: udp-header ( dst-port src-port dst-ip src-ip *ethaddr -- )
+    h# 11 ip-header
+    mac-pkt-,              \  src port
+    mac-pkt-,              \  dst port
+    d# 2 mac-pkt-,0        \  length and checksum
+;
+
+variable packetbase
+: packet packetbase @ + ;
+
+: udp-checksum ( addr -- u ) \ compute UDP checksum on packet
+    packetbase !
+    ETH.IP.UDP.LENGTH packet @ d# 1 and if
+        ETH.IP.UDP ETH.IP.UDP.LENGTH packet @ + packet
+        dup @ h# ff00 and swap !
+    then
+    ETH.IP.UDP packet
+    ETH.IP.UDP.LENGTH packet @ 1+ 2/
+    mac-checksum invert
+    d# 4 ETH.IP.SRCIP packet mac@n
+    +1c +1c +1c +1c
+    IP_PROTO_UDP +1c
+    ETH.IP.UDP.LENGTH packet @ +1c
+    invert
+;
+
+: udp-checksum? true ;
+    \ incoming udp-checksum 0= ;
+
+: udp-wrapup
+    mac-pkt-complete dup
+    ip-wrapup
+
+    OFFSET_UDP -
+    OFFSET_UDP_LENGTH packetout-off mac!
+
+    \ outgoing udp-checksum ETH.IP.UDP.CHECKSUM packetout-off !
+;
+

+ 2 - 0
j1/firmware/version.fs

@@ -0,0 +1,2 @@
+: version s" 649:659M" ;
+: builddate d# 1291578086. d# -0800 ;

+ 9 - 0
j1/synth/Makefile

@@ -0,0 +1,9 @@
+project = j1
+vendor = xilinx
+family = spartan3s
+part = xc3s1000-4ft256
+top_module = top
+
+vfiles = ../verilog/top.v ../verilog/j1.v ../verilog/ck_div.v ../verilog/uart.v
+
+include xilinx.mk

+ 12 - 0
j1/synth/j1.bmm

@@ -0,0 +1,12 @@
+ADDRESS_SPACE jram RAMB16 [0x00020000:0x00023fff]
+    BUS_BLOCK
+         j1/ram[7].ram [15:14]; 
+         j1/ram[6].ram [13:12]; 
+         j1/ram[5].ram [11:10]; 
+         j1/ram[4].ram [9:8]; 
+         j1/ram[3].ram [7:6]; 
+         j1/ram[2].ram [5:4]; 
+         j1/ram[1].ram [3:2]; 
+         j1/ram[0].ram [1:0]; 
+    END_BUS_BLOCK; 
+END_ADDRESS_SPACE; 

+ 327 - 0
j1/synth/j1.ucf

@@ -0,0 +1,327 @@
+#####################################################
+#
+# XSA-3S1000 Board FPGA pin assignment constraints
+#
+#####################################################
+#
+# Clocks
+#
+net CLKA          loc=T9  | IOSTANDARD = LVCMOS33 ; # 100MHz
+#net CLKB          loc=P8  | IOSTANDARD = LVCMOS33 ; # 50MHz
+#net CLKC          loc=R9  | IOSTANDARD = LVCMOS33 ; # ??Mhz
+#
+# Push button switches
+#
+#NET SW1_3_N       loc=K2  | IOSTANDARD = LVCMOS33 ; # Flash Block select 
+#NET SW1_4_N       loc=J4  | IOSTANDARD = LVCMOS33 ; # Flash Block
+#NET SW2_N         loc=E11 | IOSTANDARD = LVCMOS33 ; # active-low pushbutton 
+#NET SW3_N         loc=A13 | IOSTANDARD = LVCMOS33 ; # active-low pushbutton
+#
+# PS/2 Keyboard
+#
+net PS2_CLK       loc=B16 | IOSTANDARD = LVCMOS33 ; 
+net PS2_DAT       loc=E13 | IOSTANDARD = LVCMOS33 ; 
+#
+# VGA Outputs
+#
+NET VGA_BLUE<0>   LOC=C9  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_BLUE<1>   LOC=E7  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_BLUE<2>   LOC=D5  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_GREEN<0>  LOC=A8  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_GREEN<1>  LOC=A5  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_GREEN<2>  LOC=C3  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_RED<0>    LOC=C8  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_RED<1>    LOC=D6  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_RED<2>    LOC=B1  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_HSYNC_N   LOC=B7  | IOSTANDARD = LVCMOS33 ;        
+NET VGA_VSYNC_N   LOC=D8  | IOSTANDARD = LVCMOS33 ;        
+#
+# Manually assign locations for the DCMs along the bottom of the FPGA
+# because PAR sometimes places them in opposing corners and that ruins the clocks.
+#
+#INST "u1/gen_dlls.dllint" LOC="DCM_X0Y0";
+#INST "u1/gen_dlls.dllext" LOC="DCM_X1Y0";
+
+# Manually assign locations for the DCMs along the bottom of the FPGA
+# because PAR sometimes places them in opposing corners and that ruins the clocks.
+#INST "u2_dllint" LOC="DCM_X0Y0";
+#INST "u2_dllext" LOC="DCM_X1Y0";
+#
+# SDRAM memory pin assignments
+#
+#net SDRAM_clkfb  loc=N8  | IOSTANDARD = LVCMOS33 ;  # feedback SDRAM clock after PCB delays
+#net SDRAM_clkout loc=E10 | IOSTANDARD = LVCMOS33 ; # clock to SDRAM
+#net SDRAM_CKE    loc=D7  | IOSTANDARD = LVCMOS33 ;  # SDRAM clock enable
+#net SDRAM_CS_N   loc=B8  | IOSTANDARD = LVCMOS33 ;  # SDRAM chip-select
+#net SDRAM_RAS_N  loc=A9  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_CAS_N  loc=A10 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_WE_N   loc=B10 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_DQMH   loc=D9  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_DQML   loc=C10 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_A<0>   loc=B5  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<1>   loc=A4  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<2>   loc=B4  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<3>   loc=E6  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<4>   loc=E3  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<5>   loc=C1  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<6>   loc=E4  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<7>   loc=D3  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<8>   loc=C2  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<9>   loc=A3  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<10>  loc=B6  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<11>  loc=C5  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_A<12>  loc=C6  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_D<0>   loc=C15 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<1>   loc=D12 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<2>   loc=A14 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<3>   loc=B13 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<4>   loc=D11 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<5>   loc=A12 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<6>   loc=C11 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<7>   loc=D10 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<8>   loc=B11 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<9>   loc=B12 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<10>  loc=C12 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<11>  loc=B14 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<12>  loc=D14 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<13>  loc=C16 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<14>  loc=F12 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_D<15>  loc=F13 | IOSTANDARD = LVCMOS33 ; 
+#net SDRAM_BA<0>  loc=A7  | IOSTANDARD = LVCMOS33 ;  
+#net SDRAM_BA<1>  loc=C7  | IOSTANDARD = LVCMOS33 ;  
+#
+# Flash memory interface
+
+net FLASH_A<0>   LOC=N5  | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<1>   LOC=K14 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<2>   LOC=K13 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<3>   LOC=K12 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<4>   LOC=L14 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<5>   LOC=M16 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<6>   LOC=L13 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<7>   LOC=N16 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<8>   LOC=N14 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<9>   LOC=P15 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<10>  LOC=R16 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<11>  LOC=P14 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<12>  LOC=P13 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<13>  LOC=N12 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<14>  LOC=T14 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<15>  LOC=R13 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<16>  LOC=N10 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<17>  LOC=M14 | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<18>  LOC=K3  | IOSTANDARD = LVCMOS33 ;
+net FLASH_A<19>  LOC=K4  | IOSTANDARD = LVCMOS33 ;
+
+net FLASH_D<0>   LOC=M11 | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<1>   LOC=N11 | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<2>   LOC=P10 | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<3>   LOC=R10 | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<4>   LOC=T7  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<5>   LOC=R7  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<6>   LOC=N6  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<7>   LOC=M6  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<8>   LOC=T4  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<9>   LOC=R5  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<10>  LOC=T5  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<11>  LOC=P6  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<12>  LOC=M7  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<13>  LOC=R6  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<14>  LOC=N7  | IOSTANDARD = LVCMOS33 ;
+net FLASH_D<15>  LOC=P7  | IOSTANDARD = LVCMOS33 ;
+net FLASH_CE_N   LOC=R4  | IOSTANDARD = LVCMOS33 ;
+net FLASH_OE_N   LOC=P5  | IOSTANDARD = LVCMOS33 ;
+net FLASH_WE_N   LOC=M13 | IOSTANDARD = LVCMOS33 ;
+net FLASH_BYTE_N LOC=T8  | IOSTANDARD = LVCMOS33 ;
+net FLASH_RDY    LOC=L12 | IOSTANDARD = LVCMOS33 ;
+net FLASH_RST_N  LOC=P16 | IOSTANDARD = LVCMOS33 ;
+
+# FPGA Programming interface
+#
+#net FPGA_D<0>    LOC=M11 | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D0, S1, LED_C
+#net FPGA_D<1>    LOC=N11 | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D1, S7, LED_DP
+#net FPGA_D<2>    LOC=P10 | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D2, S4, LED_B
+#net FPGA_D<3>    LOC=R10 | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D3, S6, LED_A
+#net FPGA_D<4>    LOC=T7  | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D4, S5, LED_F
+#net FPGA_D<5>    LOC=R7  | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D5, S3, LED_G
+#net FPGA_D<6>    LOC=N6  | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D6, S2, LED_E
+#net FPGA_D<7>    LOC=M6  | IOSTANDARD = LVCMOS33 ; # shared with FLASH_D7, S0, LED_D
+#net FPGA_CCLK    LOC=T15 | IOSTANDARD = LVCMOS33 ;
+#net FPGA_DONE    LOC=R14 | IOSTANDARD = LVCMOS33 ;
+#net FPGA_INIT_N  LOC=N9  | IOSTANDARD = LVCMOS33 ;
+#net FPGA_PROG_N        LOC=B3  | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TCK      LOC=C14 | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TDI      LOC=A2  | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TDI_CSN       LOC=R3  | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TDO      LOC=A15 | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TDO_WRN       LOC=T3  | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TMS      LOC=C13 | IOSTANDARD = LVCMOS33 ;
+#net FPGA_TMS_BSY       LOC=P9  | IOSTANDARD = LVCMOS33 ;
+#
+# Status LED
+#
+#net S<0>          loc=M6  | IOSTANDARD = LVCMOS33 ; # FPGA_D7, LED_D 
+#net S<1>          loc=M11 | IOSTANDARD = LVCMOS33 ; # FPGA_D0, LED_C 
+#net S<2>          loc=N6  | IOSTANDARD = LVCMOS33 ; # FPGA_D6, LED_E 
+#net S<3>          loc=R7  | IOSTANDARD = LVCMOS33 ; # FPGA_D5, LED_G  
+#net S<4>          loc=P10 | IOSTANDARD = LVCMOS33 ; # FPGA_D2, LED_B 
+#net S<5>          loc=T7  | IOSTANDARD = LVCMOS33 ; # FPGA_D4, LED_F  
+#net S<6>          loc=R10 | IOSTANDARD = LVCMOS33 ; # FPGA_D3, LED_A
+#net S<7>          loc=N11 | IOSTANDARD = LVCMOS33 ; # FPGA_D1, LED_DP 
+#
+# Parallel Port
+#
+#net PPORT_load    loc=N14 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_clk     loc=P15 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_din<0>  loc=R16 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_din<1>  loc=P14 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_din<2>  loc=P13 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_din<3>  loc=N12 | IOSTANDARD = LVCMOS33 ;
+#
+#net PPORT_dout<0> loc=N5  | IOSTANDARD = LVCMOS33 ;
+#net PPORT_dout<1> loc=K14 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_dout<2> loc=K13 | IOSTANDARD = LVCMOS33 ;
+#net PPORT_dout<3> loc=T10 | IOSTANDARD = LVCMOS33 ;
+#
+#net PPORT_d<0>    loc=N14 | IOSTANDARD = LVCMOS33 ; # FLASH_A<8>  / PPORT_LOAD
+#net PPORT_d<1>    loc=P15 | IOSTANDARD = LVCMOS33 ; # FLASH_A<9>  / PPORT_CLK
+#net PPORT_d<2>    loc=R16 | IOSTANDARD = LVCMOS33 ; # FLASH_A<10> / PPORT_DIN<0>
+#net PPORT_d<3>    loc=P14 | IOSTANDARD = LVCMOS33 ; # FLASH_A<11> / PPORT_DIN<1>
+#net PPORT_d<4>    loc=P13 | IOSTANDARD = LVCMOS33 ; # FLASH_A<12> / PPORT_DIN<2>
+#net PPORT_d<5>    loc=N12 | IOSTANDARD = LVCMOS33 ; # FLASH_A<13> / PPORT_DIN<3>
+##net PPORT_d<6>    loc=T14 | IOSTANDARD = LVCMOS33 ; # FLASH_A<14>
+##net PPORT_d<7>    loc=R13 | IOSTANDARD = LVCMOS33 ; # FLASH_A<15>
+#
+#net PPORT_s<3>    loc=N5  | IOSTANDARD = LVCMOS33 ; # FLASH_A<0> / PPORT_DOUT<0>
+#net PPORT_s<4>    loc=K14 | IOSTANDARD = LVCMOS33 ; # FLASH_A<1> / PPORT_DOUT<1>
+#net PPORT_s<5>    loc=K13 | IOSTANDARD = LVCMOS33 ; # FLASH_A<2> / PPORT_DOUT<2>
+#net PPORT_s<6>    loc=T10 | IOSTANDARD = LVCMOS33 ; #            / PPORT_DOUT<3>
+#
+########################################################
+#
+# XST3.0 pins
+#
+########################################################
+#
+# BAR LED
+#
+#net BAR<1>         loc=L5  | IOSTANDARD = LVCMOS33 ; # bar led 1, PB_A0
+#net BAR<2>         loc=N2  | IOSTANDARD = LVCMOS33 ; # bar led 2, PB_A1
+#net BAR<3>         loc=M3  | IOSTANDARD = LVCMOS33 ; # bar led 3, PB_A2
+#net BAR<4>         loc=N1  | IOSTANDARD = LVCMOS33 ; # bar led 4, PB_A3
+#net BAR<5>         loc=T13 | IOSTANDARD = LVCMOS33 ; # bar led 5, PB_A4
+#net BAR<6>         loc=L15 | IOSTANDARD = LVCMOS33 ; # bar led 6,  ETHER_IRQ
+#net BAR<7>         loc=J13 | IOSTANDARD = LVCMOS33 ; # bar led 7,  USB_IRQ_N
+#net BAR<8>         loc=H15 | IOSTANDARD = LVCMOS33 ; # bar led 8,  IDE_IRQ
+#net BAR<9>         loc=J16 | IOSTANDARD = LVCMOS33 ; # bar led 9,  SLOT1_IRQ
+#net BAR<10>        loc=J14 | IOSTANDARD = LVCMOS33 ; # bar led 10, SLOT2_IRQ
+#
+# Push Buttons
+#
+#net PB1_N          loc=H4  | IOSTANDARD = LVCMOS33 ; # Shared with PB_D15
+#net PB2_N          loc=L5  | IOSTANDARD = LVCMOS33 ; # Shared with BAR1, PB_A0
+#net PB3_N          loc=N2  | IOSTANDARD = LVCMOS33 ; # Shared with BAR2, PB_A1  
+#net PB4_N          loc=M3  | IOSTANDARD = LVCMOS33 ; # Shared with BAR3, PB_A2 
+#
+# RS232 PORT
+#
+net RS232_TXD      loc=J2  | IOSTANDARD = LVCMOS33 ; # RS232 TD pin 3
+#net RS232_RXD      loc=G5  | IOSTANDARD = LVCMOS33 ; # RS232 RD pin 2
+#net RS232_CTS      loc=D1  | IOSTANDARD = LVCMOS33 ; # RS232 CTS
+#net RS232_RTS      loc=F4  | IOSTANDARD = LVCMOS33 ; # RS232 RTS
+#
+# 16 Bit Peripheral Bus
+#
+# 5-bit Peripheral address bus
+net PB_A<0>        loc=L5  | IOSTANDARD = LVCMOS33 ; # Shared with BAR1, PB2
+net PB_A<1>        loc=N2  | IOSTANDARD = LVCMOS33 ; # Shared with BAR2, PB3  
+net PB_A<2>        loc=M3  | IOSTANDARD = LVCMOS33 ; # Shared with BAR3, PB4  
+net PB_A<3>        loc=N1  | IOSTANDARD = LVCMOS33 ; # Shared with BAR4  
+net PB_A<4>        loc=T13 | IOSTANDARD = LVCMOS33 ; # Shared with BAR5
+# 16-bit peripheral data bus  
+net PB_D<0>        loc=P12 | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW1
+net PB_D<1>        loc=J1  | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW2  
+net PB_D<2>        loc=H1  | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW3  
+net PB_D<3>        loc=H3  | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW4  
+net PB_D<4>        loc=G2  | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW5  
+net PB_D<5>        loc=K15 | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW6 
+net PB_D<6>        loc=K16 | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW7 
+net PB_D<7>        loc=F15 | IOSTANDARD = LVCMOS33 ; # Shared with DIPSW8 
+net PB_D<8>        loc=E2  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_A
+net PB_D<9>        loc=E1  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_B  
+net PB_D<10>       loc=F3  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_C  
+net PB_D<11>       loc=F2  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_D  
+net PB_D<12>       loc=G4  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_E  
+net PB_D<13>       loc=G3  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_F  
+net PB_D<14>       loc=G1  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_G 
+net PB_D<15>       loc=H4  | IOSTANDARD = LVCMOS33 ; # Shared with LED2_DP, PB1  
+net PB_RD_N        loc=P2  | IOSTANDARD = LVCMOS33 ; # disk I/O read control
+net PB_WR_N        loc=R1  | IOSTANDARD = LVCMOS33 ; # disk I/O write control
+net RESET_TRIGGER  loc=D15 | IOSTANDARD = LVCMOS33 ; # Reset RESET_TRIGGER#
+#
+# IDE Interface
+#
+#net IDE_CS0_N      loc=G15 | IOSTANDARD = LVCMOS33 ; # disk register-bank select
+#net IDE_CS1_N      loc=G14 | IOSTANDARD = LVCMOS33 ; # disk register-bank select
+#net IDE_DMACK_N    loc=K1  | IOSTANDARD = LVCMOS33 ; # (out) IDE DMA acknowledge
+#net IDE_DMARQ      loc=L4  | IOSTANDARD = LVCMOS33 ; # (in) IDE DMA request
+#net IDE_IORDY      loc=L2  | IOSTANDARD = LVCMOS33 ; # (in) IDE IO ready
+#net IDE_IRQ        loc=H15 | IOSTANDARD = LVCMOS33 ; # (in) IDE interrupt # shared with BAR8
+#
+# Ethernet Controller
+# Disable if not used
+#
+net ether_cs_n    loc=G13 | IOSTANDARD = LVCMOS33 ; # (out)Ethernet chip-enable 
+net ether_aen     loc=E14 | IOSTANDARD = LVCMOS33 ; # (out) Ethernet address enable not 
+net ether_bhe_n   loc=J3  | IOSTANDARD = LVCMOS33 ; # (out) Ethernet bus high enable 
+net ether_clk     loc=R9  | IOSTANDARD = LVCMOS33 ; # (in)  Ethernet clock 
+net ether_irq     loc=L15 | IOSTANDARD = LVCMOS33 ; # (in)  Ethernet irq - Shared with BAR6
+net ether_rdy     loc=M2  | IOSTANDARD = LVCMOS33 ; # (in)  Ethernet ready
+#
+# Expansion slots
+#
+#net slot1_cs_n    loc=E15 | IOSTANDARD = LVCMOS33 ; # (out)
+#net slot1_irq     loc=J16 | IOSTANDARD = LVCMOS33 ; # (in) Shared with BAR9
+#net slot2_cs_n    loc=D16 | IOSTANDARD = LVCMOS33 ; # (out)
+#net slot2_irq     loc=J14 | IOSTANDARD = LVCMOS33 ; # (in)     Shared with BAR10
+#
+# Audio codec
+#
+#net audio_lrck    loc=R12 | IOSTANDARD = LVCMOS33 ; # (out)
+#net audio_mclk    loc=P11 | IOSTANDARD = LVCMOS33 ; # (out)
+#net audio_sclk    loc=T12 | IOSTANDARD = LVCMOS33 ; # (out)
+#net audio_sdti    loc=M10 | IOSTANDARD = LVCMOS33 ; # (out)
+#net audio_sdto    loc=K5  | IOSTANDARD = LVCMOS33 ; # (in)
+#
+# i2c
+#
+#net i2c_scl       loc=F5  | IOSTANDARD = LVCMOS33 ; #(out)
+#net i2c_sda       loc=D2  | IOSTANDARD = LVCMOS33 ; # (in/out)
+#
+# USB
+#
+#NET USB_CLK       LOC=M1  | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET USB_IRQ_N     LOC=J13 | IOSTANDARD = LVCMOS33 ; # (IN) Shared with BAR7
+#NET USB_SUSPEND   LOC=l3  | IOSTANDARD = LVCMOS33 ; # (IN)
+#
+# VIDEO DIGITIZER
+#
+#NET VIDIN_AVID    LOC=    | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET VIDIN_CLK     LOC=H16 | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET VIDIN_FID     LOC=    | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET VIDIN_HSYNC   LOC=    | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET VIDIN_IRQ     LOC=    | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET VIDIN_VSYNC   LOC=    | IOSTANDARD = LVCMOS33 ; # (IN)
+#NET VIDIN_Y<0>    LOC=H14 | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_A
+#NET VIDIN_Y<1>    LOC=M4  | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_B
+#NET VIDIN_Y<2>    LOC=P1  | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_C
+#NET VIDIN_Y<3>    LOC=N3  | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_D
+#NET VIDIN_Y<4>    LOC=M15 | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_E
+#NET VIDIN_Y<5>    LOC=H13 | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_F
+#NET VIDIN_Y<6>    LOC=G16 | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_G
+#NET VIDIN_Y<7>    LOC=N15 | IOSTANDARD = LVCMOS33 ; # (IN) Shared with LED1_DP
+#
+# Timing Constraints
+#
+NET "CLKA" TNM_NET="CLKA"; 
+TIMESPEC "TS_clk"=PERIOD "CLKA" 10 ns HIGH 50 %; 

+ 174 - 0
j1/synth/xilinx.mk

@@ -0,0 +1,174 @@
+# The top level module should define the variables below then include
+# this file.  The files listed should be in the same directory as the
+# Makefile.  
+#
+#   variable	description
+#   ----------  -------------
+#   project	project name (top level module should match this name)
+#   top_module  top level module of the project
+#   libdir	path to library directory
+#   libs	library modules used
+#   vfiles	all local .v files
+#   xilinx_cores  all local .xco files
+#   vendor      vendor of FPGA (xilinx, altera, etc.)
+#   family      FPGA device family (spartan3e) 
+#   part        FPGA part name (xc4vfx12-10-sf363)
+#   flashsize   size of flash for mcs file (16384)
+#   optfile     (optional) xst extra opttions file to put in .scr
+#   map_opts    (optional) options to give to map
+#   par_opts    (optional) options to give to par
+#   intstyle    (optional) intstyle option to all tools
+#
+#   files 		description
+#   ----------  	------------
+#   $(project).ucf	ucf file
+#
+# Library modules should have a modules.mk in their root directory,
+# namely $(libdir)/<libname>/module.mk, that simply adds to the vfiles
+# and xilinx_cores variable.
+#
+# all the .xco files listed in xilinx_cores will be generated with core, with
+# the resulting .v and .ngc files placed back in the same directory as
+# the .xco file.
+#
+# TODO: .xco files are device dependant, should use a template based system
+
+coregen_work_dir ?= ./coregen-tmp
+map_opts ?= -timing -ol high -detail -pr b -register_duplication -w
+par_opts ?= -ol high
+isedir ?= /opt/Xilinx/11.1/ISE
+xil_env ?= . $(isedir)/settings32.sh
+flashsize ?= 8192
+
+libmks = $(patsubst %,$(libdir)/%/module.mk,$(libs)) 
+mkfiles = Makefile $(libmks) xilinx.mk
+include $(libmks)
+
+corengcs = $(foreach core,$(xilinx_cores),$(core:.xco=.ngc))
+local_corengcs = $(foreach ngc,$(corengcs),$(notdir $(ngc)))
+vfiles += $(foreach core,$(xilinx_cores),$(core:.xco=.v))
+junk += $(local_corengcs)
+
+.PHONY: default xilinx_cores clean twr etwr
+default: $(project).bit $(project).mcs
+xilinx_cores: $(corengcs)
+twr: $(project).twr
+etwr: $(project)_err.twr
+
+define cp_template
+$(2): $(1)
+	cp $(1) $(2)
+endef
+$(foreach ngc,$(corengcs),$(eval $(call cp_template,$(ngc),$(notdir $(ngc)))))
+
+%.ngc %.v: %.xco
+	@echo "=== rebuilding $@"
+	if [ -d $(coregen_work_dir) ]; then \
+		rm -rf $(coregen_work_dir)/*; \
+	else \
+		mkdir -p $(coregen_work_dir); \
+	fi
+	cd $(coregen_work_dir); \
+	$(xil_env); \
+	coregen -b $$OLDPWD/$<; \
+	cd -
+	xcodir=`dirname $<`; \
+	basename=`basename $< .xco`; \
+	if [ ! -r $(coregen_work_dir/$$basename.ngc) ]; then \
+		echo "'$@' wasn't created."; \
+		exit 1; \
+	else \
+		cp $(coregen_work_dir)/$$basename.v $(coregen_work_dir)/$$basename.ngc $$xcodir; \
+	fi
+junk += $(coregen_work_dir)
+
+date = $(shell date +%F-%H-%M)
+
+# some common junk
+junk += *.xrpt
+
+programming_files: $(project).bit $(project).mcs
+	mkdir -p $@/$(date)
+	mkdir -p $@/latest
+	for x in .bit .mcs .cfi _bd.bmm; do cp $(project)$$x $@/$(date)/$(project)$$x; cp $(project)$$x $@/latest/$(project)$$x; done
+	$(xil_env); xst -help | head -1 | sed 's/^/#/' | cat - $(project).scr > $@/$(date)/$(project).scr
+
+$(project).mcs: $(project).bit
+	$(xil_env); \
+	promgen -w -s $(flashsize) -p mcs -o $@ -u 0 $^
+junk += $(project).mcs $(project).cfi $(project).prm
+
+$(project).bit: $(project)_par.ncd
+	$(xil_env); \
+	bitgen $(intstyle) -g DriveDone:yes -g StartupClk:Cclk -w $(project)_par.ncd $(project).bit
+junk += $(project).bgn $(project).bit $(project).drc $(project)_bd.bmm
+
+
+$(project)_par.ncd: $(project).ncd
+	$(xil_env); \
+	if par $(intstyle) $(par_opts) -w $(project).ncd $(project)_par.ncd; then \
+		:; \
+	else \
+		$(MAKE) etwr; \
+	fi 
+junk += $(project)_par.ncd $(project)_par.par $(project)_par.pad 
+junk += $(project)_par_pad.csv $(project)_par_pad.txt 
+junk += $(project)_par.grf $(project)_par.ptwx
+junk += $(project)_par.unroutes $(project)_par.xpi
+
+$(project).ncd: $(project).ngd
+	if [ -r $(project)_par.ncd ]; then \
+		cp $(project)_par.ncd smartguide.ncd; \
+		smartguide="-smartguide smartguide.ncd"; \
+	else \
+		smartguide=""; \
+	fi; \
+	$(xil_env); \
+	map $(intstyle) $(map_opts) $$smartguide $<
+junk += $(project).ncd $(project).pcf $(project).ngm $(project).mrp $(project).map
+junk += smartguide.ncd $(project).psr 
+junk += $(project)_summary.xml $(project)_usage.xml
+
+$(project).ngd: $(project).ngc $(project).ucf $(project).bmm
+	$(xil_env); ngdbuild $(intstyle) $(project).ngc -bm $(project).bmm
+junk += $(project).ngd $(project).bld
+
+$(project).ngc: $(vfiles) $(local_corengcs) $(project).scr $(project).prj
+	$(xil_env); xst $(intstyle) -ifn $(project).scr
+junk += xlnx_auto* $(top_module).lso $(project).srp 
+junk += netlist.lst xst $(project).ngc
+
+$(project).prj: $(vfiles) $(mkfiles)
+	for src in $(vfiles); do echo "verilog work $$src" >> $(project).tmpprj; done
+	sort -u $(project).tmpprj > $(project).prj
+	rm -f $(project).tmpprj
+junk += $(project).prj
+
+optfile += $(wildcard $(project).opt)
+top_module ?= $(project)
+$(project).scr: $(optfile) $(mkfiles) ./xilinx.opt
+	echo "run" > $@
+	echo "-p $(part)" >> $@
+	echo "-top $(top_module)" >> $@
+	echo "-ifn $(project).prj" >> $@
+	echo "-ofn $(project).ngc" >> $@
+	cat ./xilinx.opt $(optfile) >> $@
+junk += $(project).scr
+
+$(project).post_map.twr: $(project).ncd
+	$(xil_env); trce -e 10 $< $(project).pcf -o $@
+junk += $(project).post_map.twr $(project).post_map.twx smartpreview.twr
+
+$(project).twr: $(project)_par.ncd
+	$(xil_env); trce $< $(project).pcf -o $(project).twr
+junk += $(project).twr $(project).twx smartpreview.twr
+
+$(project)_err.twr: $(project)_par.ncd
+	$(xil_env); trce -e 10 $< $(project).pcf -o $(project)_err.twr
+junk += $(project)_err.twr $(project)_err.twx
+
+.gitignore: $(mkfiles)
+	echo programming_files $(junk) | sed 's, ,\n,g' > .gitignore
+
+clean::
+	rm -rf $(junk)

+ 42 - 0
j1/synth/xilinx.opt

@@ -0,0 +1,42 @@
+-ifmt mixed
+-ofmt NGC
+-opt_mode speed
+-opt_level 1
+-iuc NO
+-keep_hierarchy no
+-netlist_hierarchy as_optimized
+-rtlview no
+-glob_opt AllClockNets
+-read_cores yes
+-write_timing_constraints NO
+-cross_clock_analysis NO
+-hierarchy_separator /
+-bus_delimiter <>
+-case maintain
+-slice_utilization_ratio 100
+-bram_utilization_ratio 100
+#-dsp_utilization_ratio 100
+-safe_implementation No
+-fsm_extract YES
+-fsm_encoding Auto
+-fsm_style lut
+-ram_extract Yes
+-ram_style Auto
+-rom_extract Yes
+-rom_style Auto
+-shreg_extract YES
+-auto_bram_packing NO
+-resource_sharing YES
+-async_to_sync NO
+#-use_dsp48 auto
+-iobuf YES
+-max_fanout 500
+-register_duplication YES
+-register_balancing No
+-optimize_primitives NO
+-use_clock_enable Auto
+-use_sync_set Auto
+-use_sync_reset Auto
+-iob auto
+-equivalent_register_removal YES
+-slice_utilization_ratio_maxmargin 5

+ 41 - 0
j1/verilog/ck_div.v

@@ -0,0 +1,41 @@
+module ck_div(
+input ck_in,
+output ck_out,
+input sys_rst_i
+//output locked;
+);
+parameter DIV_BY = 1;
+parameter MULT_BY = 1;
+
+wire ck_fb;
+
+//DCM #(
+//   .CLKDV_DIVIDE(DIV_BY),
+//   .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis
+//   .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE
+//   .STARTUP_WAIT("TRUE")    // Delay configuration DONE until DCM LOCK, TRUE/FALSE
+//) DCM_inst (
+//   .CLK0(ck_fb),    
+//   .CLKDV(ck_out), 
+//   .CLKFB(ck_fb),    // DCM clock feedback
+//   .CLKIN(ck_in),     // Clock input (from IBUFG, BUFG or DCM)
+//   .RST(0)
+//);
+
+DCM #(
+   .CLKFX_MULTIPLY(MULT_BY),
+   .CLKFX_DIVIDE(DIV_BY),
+   .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis
+   .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE
+   .STARTUP_WAIT("TRUE")    // Delay configuration DONE until DCM LOCK, TRUE/FALSE
+) DCM_inst (
+   .CLK0(ck_fb),    
+   .CLKFX(ck_out), 
+   .CLKFB(ck_fb),    // DCM clock feedback
+   .CLKIN(ck_in),     // Clock input (from IBUFG, BUFG or DCM)
+   .RST(0)
+);
+
+//BUFG BUFG_inst(.I(ck_int), .O(ck_out));
+
+endmodule

+ 187 - 0
j1/verilog/j1.v

@@ -0,0 +1,187 @@
+module j1(
+   input sys_clk_i, input sys_rst_i, input [15:0] io_din,
+   output io_rd, output io_wr, output [15:0] io_addr, output [15:0] io_dout);
+
+  wire [15:0] insn;
+  wire [15:0] immediate = { 1'b0, insn[14:0] };
+
+  wire [15:0] ramrd;
+
+  reg [4:0] dsp;  // Data stack pointer
+  reg [4:0] _dsp;
+  reg [15:0] st0; // Return stack pointer
+  reg [15:0] _st0;
+  wire _dstkW;     // D stack write
+
+  reg [12:0] pc;
+  reg [12:0] _pc;
+  reg [4:0] rsp;
+  reg [4:0] _rsp;
+  reg _rstkW;     // R stack write
+  reg [15:0] _rstkD;
+  wire _ramWE;     // RAM write enable
+
+  wire [15:0] pc_plus_1;
+  assign pc_plus_1 = pc + 1;
+
+  // The D and R stacks
+  reg [15:0] dstack[0:31];
+  reg [15:0] rstack[0:31];
+  always @(posedge sys_clk_i)
+  begin
+    if (_dstkW)
+      dstack[_dsp] = st0;
+    if (_rstkW)
+      rstack[_rsp] = _rstkD;
+  end
+  wire [15:0] st1 = dstack[dsp];
+  wire [15:0] rst0 = rstack[rsp];
+
+  // st0sel is the ALU operation.  For branch and call the operation
+  // is T, for 0branch it is N.  For ALU ops it is loaded from the instruction
+  // field.
+  reg [3:0] st0sel;
+  always @*
+  begin
+    case (insn[14:13])
+      2'b00: st0sel = 0;          // ubranch
+      2'b10: st0sel = 0;          // call
+      2'b01: st0sel = 1;          // 0branch
+      2'b11: st0sel = insn[11:8]; // ALU
+      default: st0sel = 4'bxxxx;
+    endcase
+  end
+
+`define RAMS 3
+
+  genvar i;
+
+`define w (16 >> `RAMS)
+`define w1 (`w - 1)
+
+  generate 
+    for (i = 0; i < (1 << `RAMS); i=i+1) begin : ram
+      // RAMB16_S18_S18
+      RAMB16_S2_S2
+      ram(
+        .DIA(0),
+        // .DIPA(0),
+        .DOA(insn[`w*i+`w1:`w*i]),
+        .WEA(0),
+        .ENA(1),
+        .CLKA(sys_clk_i),
+        .ADDRA({_pc}),
+
+        .DIB(st1[`w*i+`w1:`w*i]),
+        // .DIPB(2'b0),
+        .WEB(_ramWE & (_st0[15:14] == 0)),
+        .ENB(|_st0[15:14] == 0),
+        .CLKB(sys_clk_i),
+        .ADDRB(_st0[15:1]),
+        .DOB(ramrd[`w*i+`w1:`w*i]));
+    end
+  endgenerate
+
+  // Compute the new value of T.
+  always @*
+  begin
+    if (insn[15])
+      _st0 = immediate;
+    else
+      case (st0sel)
+        4'b0000: _st0 = st0;
+        4'b0001: _st0 = st1;
+        4'b0010: _st0 = st0 + st1;
+        4'b0011: _st0 = st0 & st1;
+        4'b0100: _st0 = st0 | st1;
+        4'b0101: _st0 = st0 ^ st1;
+        4'b0110: _st0 = ~st0;
+        4'b0111: _st0 = {16{(st1 == st0)}};
+        4'b1000: _st0 = {16{($signed(st1) < $signed(st0))}};
+        4'b1001: _st0 = st1 >> st0[3:0];
+        4'b1010: _st0 = st0 - 1;
+        4'b1011: _st0 = rst0;
+        4'b1100: _st0 = |st0[15:14] ? io_din : ramrd;
+        4'b1101: _st0 = st1 << st0[3:0];
+        4'b1110: _st0 = {rsp, 3'b000, dsp};
+        4'b1111: _st0 = {16{(st1 < st0)}};
+        default: _st0 = 16'hxxxx;
+      endcase
+  end
+
+  wire is_alu = (insn[15:13] == 3'b011);
+  wire is_lit = (insn[15]);
+
+  assign io_rd = (is_alu & (insn[11:8] == 4'hc));
+  assign io_wr = _ramWE;
+  assign io_addr = st0;
+  assign io_dout = st1;
+
+  assign _ramWE = is_alu & insn[5];
+  assign _dstkW = is_lit | (is_alu & insn[7]);
+
+  wire [1:0] dd = insn[1:0];  // D stack delta
+  wire [1:0] rd = insn[3:2];  // R stack delta
+
+  always @*
+  begin
+    if (is_lit) begin                       // literal
+      _dsp = dsp + 1;
+      _rsp = rsp;
+      _rstkW = 0;
+      _rstkD = _pc;
+    end else if (is_alu) begin
+      _dsp = dsp + {dd[1], dd[1], dd[1], dd};
+      _rsp = rsp + {rd[1], rd[1], rd[1], rd};
+      _rstkW = insn[6];
+      _rstkD = st0;
+    end else begin                          // jump/call
+      // predicated jump is like DROP
+      if (insn[15:13] == 3'b001) begin
+        _dsp = dsp - 1;
+      end else begin
+        _dsp = dsp;
+      end
+      if (insn[15:13] == 3'b010) begin // call
+        _rsp = rsp + 1;
+        _rstkW = 1;
+        _rstkD = {pc_plus_1[14:0], 1'b0};
+      end else begin
+        _rsp = rsp;
+        _rstkW = 0;
+        _rstkD = _pc;
+      end
+    end
+  end
+
+  always @*
+  begin
+    if (sys_rst_i)
+      _pc = pc;
+    else
+      if ((insn[15:13] == 3'b000) |
+          ((insn[15:13] == 3'b001) & (|st0 == 0)) |
+          (insn[15:13] == 3'b010))
+        _pc = insn[12:0];
+      else if (is_alu & insn[12])
+        _pc = rst0[15:1];
+      else
+        _pc = pc_plus_1;
+  end
+
+  always @(posedge sys_clk_i)
+  begin
+    if (sys_rst_i) begin
+      pc <= 0;
+      dsp <= 0;
+      st0 <= 0;
+      rsp <= 0;
+    end else begin
+      dsp <= _dsp;
+      pc <= _pc;
+      st0 <= _st0;
+      rsp <= _rsp;
+    end
+  end
+
+endmodule // j1

+ 36 - 0
j1/verilog/rams.v

@@ -0,0 +1,36 @@
+module ram8_8(
+    input [7:0] dia,
+    output [7:0] doa,
+    input wea,
+    input ena,
+    input clka,
+    input [10:0] addra,
+
+    input [7:0] dib,
+    output [7:0] dob,
+    input web,
+    input enb,
+    input clkb,
+    input [10:0] addrb
+    );
+genvar i;
+generate 
+  for (i = 0; i < 4; i=i+1) begin : ramx
+    RAMB16_S2_S2 ramx(
+      .DIA(dia[2 * i + 1: 2 * i]),
+      .WEA(wea),
+      .ENA(ena),
+      .CLKA(clka),
+      .ADDRA(addra),
+      .DOA(doa[2 * i + 1: 2 * i]),
+
+      .DIB(dib[2 * i + 1: 2 * i]),
+      .WEB(web),
+      .ENB(enb),
+      .CLKB(clkb),
+      .ADDRB(addrb),
+      .DOB(dob[2 * i + 1: 2 * i])
+      );
+  end
+endgenerate
+endmodule

+ 667 - 0
j1/verilog/top.v

@@ -0,0 +1,667 @@
+module bidir_io(
+  input dir,
+  input d,
+  inout port);
+  assign port = (dir) ? 1'bz : d;
+endmodule
+
+module saturating_adder(
+    input [7:0] a,
+    input [7:0] b,
+    input [7:0] c,
+    input [7:0] d,
+    input [7:0] e,
+    input [7:0] f,
+    input [7:0] g,
+    input [7:0] h,
+    input [7:0] i,
+    output [7:0] sum);
+
+wire [10:0] fullsum = a + b + c + d + e + f + g + h + i;
+assign sum = |fullsum[10:8] ? 255 : fullsum[7:0];
+endmodule
+
+module partial(
+  input [7:0] original,
+  input alpha,
+  input [2:0] scale,  // by quarters
+  output [7:0] result
+);
+assign result = alpha ? ((scale[0] ? original[7:2] : 0) +
+                  (scale[1] ? original[7:1] : 0) +
+                  (scale[2] ? original : 0)) : 0;
+endmodule
+
+module lfsre(
+    input clk,
+    output reg [16:0] lfsr);
+wire d0;
+
+xnor(d0,lfsr[16],lfsr[13]);
+
+always @(posedge clk) begin
+    lfsr <= {lfsr[15:0],d0};
+end
+endmodule
+
+module sprite(
+  pixel_clk,
+  picsel,
+  pixel_x,
+  pixel_y,
+  sx, sy,
+  write_data, write_address, write_en, write_clk,
+  brightness,
+  alpha
+);
+  input pixel_clk;
+  input picsel;
+  input [9:0] pixel_x;
+  input [9:0] pixel_y;
+  input [9:0] sx;
+  input [9:0] sy;
+  input [8:0] write_data;
+  input [11:0] write_address;
+  input  write_en;
+  input  write_clk;
+
+  output alpha;
+  output [7:0] brightness;
+
+  wire [9:0] local_x = pixel_x - sx;
+  wire [9:0] local_y = pixel_y - sy;
+  wire [7:0] sprite_pixel;
+  RAMB16_S9_S9 spriteram(
+    .DIA(0),
+    // .DIPA(0),
+    .DOA(sprite_pixel),
+    .WEA(0),
+    .ENA(1),
+    .CLKA(pixel_clk),
+    .ADDRA({picsel, local_y[4:0], local_x[4:0]}),
+
+    .ADDRB(write_address),
+    .DIPB(write_data[8]),
+    .DIB(write_data),
+    .WEB(write_en),
+    .ENB(1),
+    .CLKB(write_clk),
+    .DOB());
+  wire sprite_outside = |(local_y[9:5]) | |(local_x[9:5]);
+  wire alpha = ~sprite_outside;
+  wire [7:0] brightness = sprite_pixel; // sprite_outside ? 0 : sprite_pixel;
+endmodule
+
+module top(
+  // Outputs
+  // s,          // Onboard LED
+  RS232_TXD,  // RS232 transmit
+  RESET_TRIGGER,      // RESET-TRIGGER#
+
+  // Inputs
+  clka,
+
+  pb_a, pb_d, pb_rd_n, pb_wr_n,
+
+  ether_cs_n, ether_aen, ether_bhe_n, ether_clk, ether_irq, ether_rdy,
+
+  // Flash
+  flash_a, flash_d, 
+  flash_ce_n, flash_oe_n, flash_we_n, flash_byte_n, flash_rdy, flash_rst_n,
+
+  // PS/2 Keyboard
+  ps2_clk, ps2_dat,
+
+  // Pushbuttons
+  sw2_n, sw3_n,
+
+  // VGA
+  vga_red, vga_green, vga_blue, vga_hsync_n, vga_vsync_n,
+
+  );
+  
+  // output [7:0] s;
+  output RS232_TXD;
+  output RESET_TRIGGER;
+  inout [4:0] pb_a;
+  output ether_cs_n;
+  output ether_aen;
+  output ether_bhe_n;
+  output pb_rd_n;
+  output pb_wr_n;
+
+  input clka;
+  input ether_clk;
+  input ether_irq;
+  input ether_rdy;
+
+  inout [15:0] pb_d;
+
+  output [19:0] flash_a;
+
+  inout [15:0] flash_d;
+
+  output flash_ce_n;
+  output flash_oe_n;
+  output flash_we_n;
+  output flash_byte_n;
+  output flash_rdy;
+  output flash_rst_n;
+
+  reg ps2_clk_dir;
+  reg ps2_dat_dir;
+  reg ps2_clk_d;
+  reg ps2_dat_d;
+  inout ps2_clk;
+  inout ps2_dat;
+  bidir_io ps2_clkb(.dir(ps2_clk_dir), .d(ps2_clk_d), .port(ps2_clk));
+  bidir_io ps2_datb(.dir(ps2_dat_dir), .d(ps2_dat_d), .port(ps2_dat));
+
+  input sw2_n;
+  input sw3_n;
+
+  output [2:0] vga_red;
+  output [2:0] vga_green;
+  output [2:0] vga_blue;
+  output vga_hsync_n;
+  output vga_vsync_n;
+
+  wire j1_io_rd;
+  wire j1_io_wr;
+  wire [15:0] j1_io_addr;
+  reg  [15:0] j1_io_din;
+  wire [15:0] j1_io_dout;
+
+  wire sys_clk;
+  ck_div #(.DIV_BY(12), .MULT_BY(4)) sys_ck_gen(.ck_in(clka), .ck_out(sys_clk));
+
+  // ================================================
+  // Hardware multiplier
+
+  reg [15:0] mult_a;
+  reg [15:0] mult_b;
+  wire [31:0] mult_p;
+  MULT18X18 mulinsn(.A(mult_a), .B(mult_b), .P(mult_p));
+//   MULT18X18SIO #(
+//     .AREG(0),
+//     .BREG(0),
+//     .PREG(0))
+//   MULT18X18SIO(
+//     .A(mult_a),
+//     .B(mult_b),
+//     .P(mult_p));
+
+  // ================================================
+  // 32-bit 1-MHz system clock
+
+  reg  [5:0]  clockus;
+  wire [5:0]  _clockus = (clockus == 32) ? 0 : (clockus + 1);
+  reg  [31:0] clock;
+  wire [31:0] _clock = (clockus == 32) ? (clock + 1) : (clock);
+
+  always @(posedge sys_clk)
+  begin
+    clockus <= _clockus;
+    clock <= _clock;
+  end
+
+  // reg [7:0] s;
+  reg RS232_TXD;
+  reg RESET_TRIGGER;
+
+  reg ether_cs_n;
+  reg ether_aen;
+  reg ether_bhe_n;
+  reg ddir;
+
+  reg [15:0] pb_dout;
+  assign pb_d = (ddir) ? 16'bz : pb_dout;
+  reg pb_rd_n;
+  reg pb_wr_n;
+
+  reg pb_a_dir;
+  reg [4:0] pb_aout;
+  assign pb_a = pb_a_dir ? 5'bz : pb_aout;
+
+  reg flash_ddir;
+  reg [19:0] flash_a;
+  reg [15:0] flash_dout;
+  assign flash_d[14:0] = (flash_ddir) ? 15'bz : flash_dout[14:0];
+  assign flash_d[15] = (flash_ddir & flash_byte_n) ? 1'bz : flash_dout[15];
+  reg flash_ce_n;
+  reg flash_oe_n;
+  reg flash_we_n;
+  reg flash_byte_n;
+  reg flash_rdy;
+  reg flash_rst_n;
+
+  reg [12:0] vga_scroll;
+  reg [13:0] vga_spritea;
+  reg [9:0] vga_spritex[7:0];
+  reg [9:0] vga_spritey[7:0];
+  reg vga_addsprites;
+  reg [10:0] vga_spritec0;
+  reg [10:0] vga_spritec1;
+  reg [10:0] vga_spritec2;
+  reg [10:0] vga_spritec3;
+  reg [10:0] vga_spritec4;
+  reg [10:0] vga_spritec5;
+  reg [10:0] vga_spritec6;
+  reg [10:0] vga_spritec7;
+  wire [9:0] vga_line;
+  reg [7:0] vga_spritesel;
+
+  always @(posedge sys_clk)
+  begin
+    if (j1_io_wr) begin
+      case (j1_io_addr)
+      // 16'h4000: s <= j1_io_dout;
+
+      16'h4100: flash_ddir <= j1_io_dout;
+      16'h4102: flash_ce_n <= j1_io_dout;
+      16'h4104: flash_oe_n <= j1_io_dout;
+      16'h4106: flash_we_n <= j1_io_dout;
+      16'h4108: flash_byte_n <= j1_io_dout;
+      16'h410a: flash_rdy <= j1_io_dout;
+      16'h410c: flash_rst_n <= j1_io_dout;
+      16'h410e: flash_a[15:0] <= j1_io_dout;
+      16'h4110: flash_a[19:16] <= j1_io_dout;
+      16'h4112: flash_dout <= j1_io_dout;
+
+      16'h4200: ps2_clk_d <= j1_io_dout;
+      16'h4202: ps2_dat_d <= j1_io_dout;
+      16'h4204: ps2_clk_dir <= j1_io_dout;
+      16'h4206: ps2_dat_dir <= j1_io_dout;
+
+      16'h4300: vga_scroll <= j1_io_dout;
+      16'h4302: vga_spritea <= j1_io_dout;
+      // 16'h4304: vga_spriteport
+      16'h4308: vga_addsprites <= j1_io_dout;
+
+      16'h4400: vga_spritex[0] <= j1_io_dout;
+      16'h4402: vga_spritey[0] <= j1_io_dout;
+      16'h4404: vga_spritex[1] <= j1_io_dout;
+      16'h4406: vga_spritey[1] <= j1_io_dout;
+      16'h4408: vga_spritex[2] <= j1_io_dout;
+      16'h440a: vga_spritey[2] <= j1_io_dout;
+      16'h440c: vga_spritex[3] <= j1_io_dout;
+      16'h440e: vga_spritey[3] <= j1_io_dout;
+      16'h4410: vga_spritex[4] <= j1_io_dout;
+      16'h4412: vga_spritey[4] <= j1_io_dout;
+      16'h4414: vga_spritex[5] <= j1_io_dout;
+      16'h4416: vga_spritey[5] <= j1_io_dout;
+      16'h4418: vga_spritex[6] <= j1_io_dout;
+      16'h441a: vga_spritey[6] <= j1_io_dout;
+      16'h441c: vga_spritex[7] <= j1_io_dout;
+      16'h441e: vga_spritey[7] <= j1_io_dout;
+
+      16'h4420: vga_spritec0 <= j1_io_dout;
+      16'h4422: vga_spritec1 <= j1_io_dout;
+      16'h4424: vga_spritec2 <= j1_io_dout;
+      16'h4426: vga_spritec3 <= j1_io_dout;
+      16'h4428: vga_spritec4 <= j1_io_dout;
+      16'h442a: vga_spritec5 <= j1_io_dout;
+      16'h442c: vga_spritec6 <= j1_io_dout;
+      16'h442e: vga_spritec7 <= j1_io_dout;
+
+      16'h4430: vga_spritesel[0] <= j1_io_dout;
+      16'h4432: vga_spritesel[1] <= j1_io_dout;
+      16'h4434: vga_spritesel[2] <= j1_io_dout;
+      16'h4436: vga_spritesel[3] <= j1_io_dout;
+      16'h4438: vga_spritesel[4] <= j1_io_dout;
+      16'h443a: vga_spritesel[5] <= j1_io_dout;
+      16'h443c: vga_spritesel[6] <= j1_io_dout;
+      16'h443e: vga_spritesel[7] <= j1_io_dout;
+
+      16'h5000: RS232_TXD <= j1_io_dout;
+      16'h5001: RESET_TRIGGER <= j1_io_dout;
+      16'h5100: ether_cs_n <= j1_io_dout;
+      16'h5101: ether_aen <= j1_io_dout;
+      16'h5102: ether_bhe_n <= j1_io_dout;
+      16'h5103: pb_aout <= j1_io_dout;
+      16'h5104: ddir <= j1_io_dout;
+      16'h5105: pb_dout <= j1_io_dout;
+      16'h5106: pb_rd_n <= j1_io_dout;
+      16'h5107: pb_wr_n <= j1_io_dout;
+      // 5108
+      // 5109
+      16'h510a: pb_a_dir <= j1_io_dout;
+
+      16'h6100: mult_a <= j1_io_dout;
+      16'h6102: mult_b <= j1_io_dout;
+
+      endcase
+    end
+  end
+
+  always @*
+  begin
+    case (j1_io_addr)
+    16'h4112: j1_io_din = flash_d;
+
+    16'h4200: j1_io_din = ps2_clk;
+    16'h4202: j1_io_din = ps2_dat;
+
+    16'h4300: j1_io_din = vga_scroll;
+    16'h4306: j1_io_din = vga_line;
+
+    16'h4500: j1_io_din = sw2_n;
+    16'h4502: j1_io_din = sw3_n;
+
+    16'h5103: j1_io_din = pb_a;
+    16'h5105: j1_io_din = pb_d;
+    16'h5108: j1_io_din = ether_rdy;
+    16'h5109: j1_io_din = ether_irq;
+
+    16'h6000: j1_io_din = clock[15:0];
+    16'h6002: j1_io_din = clock[31:16];
+
+    16'h6104: j1_io_din = mult_p[15:0];
+    16'h6106: j1_io_din = mult_p[31:16];
+
+    default: j1_io_din = 16'h0946;
+    endcase
+  end
+
+  reg [10:0] reset_count = 1000;
+  wire sys_rst_i = |reset_count;
+   
+  always @(posedge sys_clk) begin
+    if (sys_rst_i)
+      reset_count <= reset_count - 1;
+  end 
+
+  j1 j1(
+       // Inputs
+       .sys_clk_i                 (sys_clk),
+       .sys_rst_i                 (sys_rst_i),
+
+       .io_rd(j1_io_rd),
+       .io_wr(j1_io_wr),
+       .io_addr(j1_io_addr),
+       .io_din(j1_io_din),
+       .io_dout(j1_io_dout)
+       );
+
+  /*
+  uart uart(
+            // Outputs
+            .uart_busy                 (uart_busy),
+            .uart_tx                   (RS232_TXD),
+            // Inputs
+            .uart_wr_i                 (j1_uart_we),
+            .uart_dat_i                (j1_io_dout),
+            .sys_clk_i                 (sys_clk_i),
+            .sys_rst_i                 (sys_rst_i));
+  */
+
+  // ================================================
+  // VGA
+
+  wire vga_clk;
+  ck_div #(.DIV_BY(4), .MULT_BY(2)) vga_ck_gen(.ck_in(clka), .ck_out(vga_clk));
+
+  reg [10:0] CounterX;
+  reg [9:0] CounterY;
+  wire CounterXmaxed = (CounterX==1040);
+
+  always @(posedge vga_clk)
+  if(CounterXmaxed)
+    CounterX <= 0;
+  else
+    CounterX <= CounterX + 1;
+
+  wire [9:0] _CounterY = (CounterY == 666) ? 0 : (CounterY + 1);
+  always @(posedge vga_clk)
+  if(CounterXmaxed)
+      CounterY <= _CounterY;
+
+  reg vga_HS, vga_VS;
+  always @(posedge vga_clk)
+  begin
+    vga_HS <= (53 <= CounterX) & (CounterX < (53 + 120));
+    vga_VS <= (35 <= CounterY) & (CounterY < (35 + 6));
+  end
+
+  // Character RAM is 2K
+  wire [10:0] xx = (CounterX - (53 + 120 + 61));
+  wire [10:0] xx_1 = (CounterX - (53 + 120 + 61) + 1);
+  // standard timing, except (600-512)/2=44 at top and bottom
+  wire [10:0] yy = (CounterY - (35 + 6 + 21 + 44));
+  wire [10:0] column = xx[10:1];
+  wire [10:0] column_1 = xx_1[10:1];
+  wire [10:0] row    = yy[10:1];
+  wire [7:0] glyph;
+
+  wire [10:0] picaddr = {(row[7:3] + vga_scroll[4:0]), column_1[8:3]};
+
+//   genvar i;
+//   generate 
+//     for (i = 0; i < 4; i=i+1) begin : picture
+//       RAMB16_S2_S2 picture(
+//         .DIA(0),
+//         // .DIPA(0),
+//         .DOA(glyph[2 * i + 1: 2 * i]),
+//         .WEA(0),
+//         .ENA(1),
+//         .CLKA(vga_clk),
+//         .ADDRA(spicaddr),
+// 
+//         // .DIPB(0),
+//         .DIB(j1_io_dout[2 * i + 1: 2 * i]),
+//         .WEB(j1_io_wr & (j1_io_addr[15:13] == 3'b100)),
+//         .ENB(1),
+//         .CLKB(sys_clk),
+//         .ADDRB(j1_io_addr),
+//         .DOB());
+//     end
+//   endgenerate
+
+//   RAMB16_S9_S9 picture(
+//     .DIA(0),
+//     // .DIPA(0),
+//     .DOA(glyph),
+//     .WEA(0),
+//     .ENA(1),
+//     .CLKA(vga_clk),
+//     .ADDRA(picaddr),
+// 
+//     .DIPB(0),
+//     .DIB(j1_io_dout),
+//     .WEB(j1_io_wr & (j1_io_addr[15:13] == 3'b100)),
+//     .ENB(1),
+//     .CLKB(sys_clk),
+//     .ADDRB(j1_io_addr),
+//     .DOB());
+  wire pic_w = j1_io_wr & (j1_io_addr[15:13] == 3'b100);
+  ram8_8 picture(
+    .dia(0), .doa(glyph), .wea(0),     .ena(1), .clka(vga_clk), .addra(picaddr),
+    .dib(j1_io_dout),              .web(pic_w), .enb(1), .clkb(sys_clk), .addrb(j1_io_addr));
+
+  wire charout;
+  RAMB16_S1_S9 chars(
+    .DIA(0),
+    // .DIPA(0),
+    .DOA(charout),
+    .WEA(0),
+    .ENA(1),
+    .CLKA(vga_clk),
+    .ADDRA({glyph, row[2:0], ~column[2:0]}),
+
+    .DIPB(0),
+    .DIB(j1_io_dout),
+    // .DIPB(2'b0),
+    .WEB(j1_io_wr & (j1_io_addr[15:12] == 4'hf)),
+    .ENB(1),
+    .CLKB(sys_clk),
+    .ADDRB(j1_io_addr),
+    .DOB());
+
+  reg [10:0] regxx;
+  always @(posedge vga_clk)
+  begin
+    regxx <= xx;
+  end
+
+  wire [63:0] sprite_pixels;
+  wire [7:0] alpha;
+  genvar i;
+  generate
+    for (i = 0; i < 8; i=i+1) begin : sprite_n
+      sprite sprite_n(
+        .pixel_clk(vga_clk),
+        .picsel(vga_spritesel[i]),
+        .pixel_x(regxx),
+        .pixel_y(yy),
+        .sx(vga_spritex[i]),
+        .sy(vga_spritey[i]),
+        .write_data(j1_io_dout),
+        .write_address(vga_spritea),
+        .write_en(j1_io_wr & (j1_io_addr == 16'h4304) & (vga_spritea[13:11] == i)),
+        .write_clk(sys_clk),
+        .alpha(alpha[i]),
+        .brightness(sprite_pixels[8*i+7:8*i]));
+    end
+  endgenerate
+
+  // wire [10:0] brightsum = bright[0] + bright[1] + bright[2] + bright[3] + bright[4] + bright[5] + bright[6] + bright[7];
+  // wire [7:0] brightness = |brightsum[10:8] ? 255 : brightsum[7:0];
+  // wire [7:0] final_bright = |alpha ? 255 : 0;
+
+  // wire [7:0] final_bright = sprite_pixels[39:32];
+
+  wire [7:0] sprite0 = sprite_pixels[7:0];
+  wire [7:0] sprite1 = sprite_pixels[15:8];
+  wire [7:0] sprite2 = sprite_pixels[23:16];
+  wire [7:0] sprite3 = sprite_pixels[31:24];
+  wire [7:0] sprite4 = sprite_pixels[39:32];
+  wire [7:0] sprite5 = sprite_pixels[47:40];
+  wire [7:0] sprite6 = sprite_pixels[55:48];
+  wire [7:0] sprite7 = sprite_pixels[63:56];
+
+  reg [10:0] fullsum;
+  reg [7:0] final_bright;
+
+  wire [16:0] lfsr;
+  lfsre lfsr0(
+    .clk(vga_clk),
+    .lfsr(lfsr));
+  wire [7:0] charout8 = {8{charout}};
+  wire [7:0] dither = {lfsr[0], lfsr[4], lfsr[8], lfsr[12], lfsr[16]} | charout8;
+
+  wire [7:0] r0;
+  wire [7:0] r1;
+  wire [7:0] r2;
+  wire [7:0] r3;
+  wire [7:0] r4;
+  wire [7:0] r5;
+  wire [7:0] r6;
+  wire [7:0] r7;
+  wire [7:0] g0;
+  wire [7:0] g1;
+  wire [7:0] g2;
+  wire [7:0] g3;
+  wire [7:0] g4;
+  wire [7:0] g5;
+  wire [7:0] g6;
+  wire [7:0] g7;
+  wire [7:0] b0;
+  wire [7:0] b1;
+  wire [7:0] b2;
+  wire [7:0] b3;
+  wire [7:0] b4;
+  wire [7:0] b5;
+  wire [7:0] b6;
+  wire [7:0] b7;
+
+  wire [2:0] spr0r = vga_spritec0[10:8];
+  wire [2:0] spr1r = vga_spritec1[10:8];
+  wire [2:0] spr2r = vga_spritec2[10:8];
+  wire [2:0] spr3r = vga_spritec3[10:8];
+  wire [2:0] spr4r = vga_spritec4[10:8];
+  wire [2:0] spr5r = vga_spritec5[10:8];
+  wire [2:0] spr6r = vga_spritec6[10:8];
+  wire [2:0] spr7r = vga_spritec7[10:8];
+  wire [2:0] spr0g = vga_spritec0[6:4];
+  wire [2:0] spr1g = vga_spritec1[6:4];
+  wire [2:0] spr2g = vga_spritec2[6:4];
+  wire [2:0] spr3g = vga_spritec3[6:4];
+  wire [2:0] spr4g = vga_spritec4[6:4];
+  wire [2:0] spr5g = vga_spritec5[6:4];
+  wire [2:0] spr6g = vga_spritec6[6:4];
+  wire [2:0] spr7g = vga_spritec7[6:4];
+  wire [2:0] spr0b = vga_spritec0[2:0];
+  wire [2:0] spr1b = vga_spritec1[2:0];
+  wire [2:0] spr2b = vga_spritec2[2:0];
+  wire [2:0] spr3b = vga_spritec3[2:0];
+  wire [2:0] spr4b = vga_spritec4[2:0];
+  wire [2:0] spr5b = vga_spritec5[2:0];
+  wire [2:0] spr6b = vga_spritec6[2:0];
+  wire [2:0] spr7b = vga_spritec7[2:0];
+
+  partial pr0(sprite0, alpha[0], spr0r, r0);
+  partial pr1(sprite1, alpha[1], spr1r, r1);
+  partial pr2(sprite2, alpha[2], spr2r, r2);
+  partial pr3(sprite3, alpha[3], spr3r, r3);
+  partial pr4(sprite4, alpha[4], spr4r, r4);
+  partial pr5(sprite5, alpha[5], spr5r, r5);
+  partial pr6(sprite6, alpha[6], spr6r, r6);
+  partial pr7(sprite7, alpha[7], spr7r, r7);
+
+  partial pg0(sprite0, alpha[0], spr0g, g0);
+  partial pg1(sprite1, alpha[1], spr1g, g1);
+  partial pg2(sprite2, alpha[2], spr2g, g2);
+  partial pg3(sprite3, alpha[3], spr3g, g3);
+  partial pg4(sprite4, alpha[4], spr4g, g4);
+  partial pg5(sprite5, alpha[5], spr5g, g5);
+  partial pg6(sprite6, alpha[6], spr6g, g6);
+  partial pg7(sprite7, alpha[7], spr7g, g7);
+
+  partial pb0(sprite0, alpha[0], spr0b, b0);
+  partial pb1(sprite1, alpha[1], spr1b, b1);
+  partial pb2(sprite2, alpha[2], spr2b, b2);
+  partial pb3(sprite3, alpha[3], spr3b, b3);
+  partial pb4(sprite4, alpha[4], spr4b, b4);
+  partial pb5(sprite5, alpha[5], spr5b, b5);
+  partial pb6(sprite6, alpha[6], spr6b, b6);
+  partial pb7(sprite7, alpha[7], spr7b, b7);
+
+  wire [7:0] sat_r;
+  saturating_adder add_r(r0, r1, r2, r3, r4, r5, r6, r7, dither, sat_r);
+  wire [7:0] sat_g;
+  saturating_adder add_g(g0, g1, g2, g3, g4, g5, g6, g7, dither, sat_g);
+  wire [7:0] sat_b;
+  saturating_adder add_b(b0, b1, b2, b3, b4, b5, b6, b7, dither, sat_b);
+
+  always @*
+  begin
+    if(vga_addsprites) begin
+      final_bright = sat_r;
+    end else begin
+      if(alpha[0])      final_bright = sprite0;
+      else if(alpha[1]) final_bright = sprite1;
+      else if(alpha[2]) final_bright = sprite2;
+      else if(alpha[3]) final_bright = sprite3;
+      else if(alpha[4]) final_bright = sprite4;
+      else if(alpha[5]) final_bright = sprite5;
+      else if(alpha[6]) final_bright = sprite6;
+      else if(alpha[7]) final_bright = sprite7;
+      else
+        final_bright = 0;
+    end
+  end
+
+  wire active = ((53 + 120 + 61) <= CounterX) & (CounterX < (53 + 120 + 61 + 800)) & ((35 + 6 + 21 + 44) < CounterY) & (CounterY < (35 + 6 + 21 + 44 + 512));
+  assign vga_line = yy;
+  // wire [2:0] vga_red = active ? (charout ? 7 : 0) : 0;
+  // wire [2:0] vga_red = active ? final_bright[7:5] : 0;
+  // wire [2:0] vga_green = active ? final_bright[7:5] : 0;
+  // wire [2:0] vga_blue = active ? final_bright[7:5] : 0;
+  wire [2:0] vga_red = active ? sat_r[7:5] : 0;
+  wire [2:0] vga_green = active ? sat_g[7:5] : 0;
+  wire [2:0] vga_blue = active ? sat_b[7:5] : 0;
+  wire vga_hsync_n = ~vga_HS;
+  wire vga_vsync_n = ~vga_VS;
+
+endmodule // top
+

BIN
python/471fcf9e.png


+ 8 - 0
python/duplicator.py

@@ -0,0 +1,8 @@
+class Duplicator(object):
+    def __init__(self, objs):
+        self.objs = objs
+    def __getattr__(self, name):
+        def bcast(*args):
+            return [o.__getattribute__(name)(*args) for o in self.objs]
+        return bcast
+

+ 1 - 0
python/gameduino/__init__.py

@@ -0,0 +1 @@
+from gameduino.registers import *

+ 207 - 0
python/gameduino/base.py

@@ -0,0 +1,207 @@
+import struct
+
+ascii_glyphs = [
+0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x18,  0x18,  0x18,  0x18,  0x18,  0x00,  0x18,  0x00, 
+0x6c,  0x6c,  0x6c,  0x00,  0x00,  0x00,  0x00,  0x00,  0x36,  0x36,  0x7f,  0x36,  0x7f,  0x36,  0x36,  0x00, 
+0x0c,  0x3f,  0x68,  0x3e,  0x0b,  0x7e,  0x18,  0x00,  0x60,  0x66,  0x0c,  0x18,  0x30,  0x66,  0x06,  0x00, 
+0x38,  0x6c,  0x6c,  0x38,  0x6d,  0x66,  0x3b,  0x00,  0x0c,  0x18,  0x30,  0x00,  0x00,  0x00,  0x00,  0x00, 
+0x0c,  0x18,  0x30,  0x30,  0x30,  0x18,  0x0c,  0x00,  0x30,  0x18,  0x0c,  0x0c,  0x0c,  0x18,  0x30,  0x00, 
+0x00,  0x18,  0x7e,  0x3c,  0x7e,  0x18,  0x00,  0x00,  0x00,  0x18,  0x18,  0x7e,  0x18,  0x18,  0x00,  0x00, 
+0x00,  0x00,  0x00,  0x00,  0x00,  0x18,  0x18,  0x30,  0x00,  0x00,  0x00,  0x7e,  0x00,  0x00,  0x00,  0x00, 
+0x00,  0x00,  0x00,  0x00,  0x00,  0x18,  0x18,  0x00,  0x00,  0x06,  0x0c,  0x18,  0x30,  0x60,  0x00,  0x00, 
+0x3c,  0x66,  0x6e,  0x7e,  0x76,  0x66,  0x3c,  0x00,  0x18,  0x38,  0x18,  0x18,  0x18,  0x18,  0x7e,  0x00, 
+0x3c,  0x66,  0x06,  0x0c,  0x18,  0x30,  0x7e,  0x00,  0x3c,  0x66,  0x06,  0x1c,  0x06,  0x66,  0x3c,  0x00, 
+0x0c,  0x1c,  0x3c,  0x6c,  0x7e,  0x0c,  0x0c,  0x00,  0x7e,  0x60,  0x7c,  0x06,  0x06,  0x66,  0x3c,  0x00, 
+0x1c,  0x30,  0x60,  0x7c,  0x66,  0x66,  0x3c,  0x00,  0x7e,  0x06,  0x0c,  0x18,  0x30,  0x30,  0x30,  0x00, 
+0x3c,  0x66,  0x66,  0x3c,  0x66,  0x66,  0x3c,  0x00,  0x3c,  0x66,  0x66,  0x3e,  0x06,  0x0c,  0x38,  0x00, 
+0x00,  0x00,  0x18,  0x18,  0x00,  0x18,  0x18,  0x00,  0x00,  0x00,  0x18,  0x18,  0x00,  0x18,  0x18,  0x30, 
+0x0c,  0x18,  0x30,  0x60,  0x30,  0x18,  0x0c,  0x00,  0x00,  0x00,  0x7e,  0x00,  0x7e,  0x00,  0x00,  0x00, 
+0x30,  0x18,  0x0c,  0x06,  0x0c,  0x18,  0x30,  0x00,  0x3c,  0x66,  0x0c,  0x18,  0x18,  0x00,  0x18,  0x00, 
+
+0x3c,  0x66,  0x6e,  0x6a,  0x6e,  0x60,  0x3c,  0x00,  0x3c,  0x66,  0x66,  0x7e,  0x66,  0x66,  0x66,  0x00, 
+0x7c,  0x66,  0x66,  0x7c,  0x66,  0x66,  0x7c,  0x00,  0x3c,  0x66,  0x60,  0x60,  0x60,  0x66,  0x3c,  0x00, 
+0x78,  0x6c,  0x66,  0x66,  0x66,  0x6c,  0x78,  0x00,  0x7e,  0x60,  0x60,  0x7c,  0x60,  0x60,  0x7e,  0x00, 
+0x7e,  0x60,  0x60,  0x7c,  0x60,  0x60,  0x60,  0x00,  0x3c,  0x66,  0x60,  0x6e,  0x66,  0x66,  0x3c,  0x00, 
+0x66,  0x66,  0x66,  0x7e,  0x66,  0x66,  0x66,  0x00,  0x7e,  0x18,  0x18,  0x18,  0x18,  0x18,  0x7e,  0x00, 
+0x3e,  0x0c,  0x0c,  0x0c,  0x0c,  0x6c,  0x38,  0x00,  0x66,  0x6c,  0x78,  0x70,  0x78,  0x6c,  0x66,  0x00, 
+0x60,  0x60,  0x60,  0x60,  0x60,  0x60,  0x7e,  0x00,  0x63,  0x77,  0x7f,  0x6b,  0x6b,  0x63,  0x63,  0x00, 
+0x66,  0x66,  0x76,  0x7e,  0x6e,  0x66,  0x66,  0x00,  0x3c,  0x66,  0x66,  0x66,  0x66,  0x66,  0x3c,  0x00, 
+0x7c,  0x66,  0x66,  0x7c,  0x60,  0x60,  0x60,  0x00,  0x3c,  0x66,  0x66,  0x66,  0x6a,  0x6c,  0x36,  0x00, 
+0x7c,  0x66,  0x66,  0x7c,  0x6c,  0x66,  0x66,  0x00,  0x3c,  0x66,  0x60,  0x3c,  0x06,  0x66,  0x3c,  0x00, 
+0x7e,  0x18,  0x18,  0x18,  0x18,  0x18,  0x18,  0x00,  0x66,  0x66,  0x66,  0x66,  0x66,  0x66,  0x3c,  0x00, 
+0x66,  0x66,  0x66,  0x66,  0x66,  0x3c,  0x18,  0x00,  0x63,  0x63,  0x6b,  0x6b,  0x7f,  0x77,  0x63,  0x00, 
+0x66,  0x66,  0x3c,  0x18,  0x3c,  0x66,  0x66,  0x00,  0x66,  0x66,  0x66,  0x3c,  0x18,  0x18,  0x18,  0x00, 
+0x7e,  0x06,  0x0c,  0x18,  0x30,  0x60,  0x7e,  0x00,  0x7c,  0x60,  0x60,  0x60,  0x60,  0x60,  0x7c,  0x00, 
+0x00,  0x60,  0x30,  0x18,  0x0c,  0x06,  0x00,  0x00,  0x3e,  0x06,  0x06,  0x06,  0x06,  0x06,  0x3e,  0x00, 
+0x18,  0x3c,  0x66,  0x42,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xff, 
+
+0x1c,  0x36,  0x30,  0x7c,  0x30,  0x30,  0x7e,  0x00,  0x00,  0x00,  0x3c,  0x06,  0x3e,  0x66,  0x3e,  0x00, 
+0x60,  0x60,  0x7c,  0x66,  0x66,  0x66,  0x7c,  0x00,  0x00,  0x00,  0x3c,  0x66,  0x60,  0x66,  0x3c,  0x00, 
+0x06,  0x06,  0x3e,  0x66,  0x66,  0x66,  0x3e,  0x00,  0x00,  0x00,  0x3c,  0x66,  0x7e,  0x60,  0x3c,  0x00, 
+0x1c,  0x30,  0x30,  0x7c,  0x30,  0x30,  0x30,  0x00,  0x00,  0x00,  0x3e,  0x66,  0x66,  0x3e,  0x06,  0x3c, 
+0x60,  0x60,  0x7c,  0x66,  0x66,  0x66,  0x66,  0x00,  0x18,  0x00,  0x38,  0x18,  0x18,  0x18,  0x3c,  0x00, 
+0x18,  0x00,  0x38,  0x18,  0x18,  0x18,  0x18,  0x70,  0x60,  0x60,  0x66,  0x6c,  0x78,  0x6c,  0x66,  0x00, 
+0x38,  0x18,  0x18,  0x18,  0x18,  0x18,  0x3c,  0x00,  0x00,  0x00,  0x36,  0x7f,  0x6b,  0x6b,  0x63,  0x00, 
+0x00,  0x00,  0x7c,  0x66,  0x66,  0x66,  0x66,  0x00,  0x00,  0x00,  0x3c,  0x66,  0x66,  0x66,  0x3c,  0x00, 
+0x00,  0x00,  0x7c,  0x66,  0x66,  0x7c,  0x60,  0x60,  0x00,  0x00,  0x3e,  0x66,  0x66,  0x3e,  0x06,  0x07, 
+0x00,  0x00,  0x6c,  0x76,  0x60,  0x60,  0x60,  0x00,  0x00,  0x00,  0x3e,  0x60,  0x3c,  0x06,  0x7c,  0x00, 
+0x30,  0x30,  0x7c,  0x30,  0x30,  0x30,  0x1c,  0x00,  0x00,  0x00,  0x66,  0x66,  0x66,  0x66,  0x3e,  0x00, 
+0x00,  0x00,  0x66,  0x66,  0x66,  0x3c,  0x18,  0x00,  0x00,  0x00,  0x63,  0x6b,  0x6b,  0x7f,  0x36,  0x00, 
+0x00,  0x00,  0x66,  0x3c,  0x18,  0x3c,  0x66,  0x00,  0x00,  0x00,  0x66,  0x66,  0x66,  0x3e,  0x06,  0x3c, 
+0x00,  0x00,  0x7e,  0x0c,  0x18,  0x30,  0x7e,  0x00,  0x0c,  0x18,  0x18,  0x70,  0x18,  0x18,  0x0c,  0x00, 
+0x18,  0x18,  0x18,  0x00,  0x18,  0x18,  0x18,  0x00,  0x30,  0x18,  0x18,  0x0e,  0x18,  0x18,  0x30,  0x00, 
+0x31,  0x6b,  0x46,  0x00,  0x00,  0x00,  0x00,  0x00,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+]
+
+from gameduino.registers import *
+
+# BaseGameduino is the common base for the Gameduino objects in remote and sim
+
+class BaseGameduino(object):
+
+    def coldstart(self):
+        self.wr(J1_RESET, 1)
+        self.fill(RAM_PIC, 0, 10 * 1024)
+        for i in range(512):
+            self.sprite(i, 400, 400, 0, 0, 0)
+        self.wr16(SPR_DISABLE, 0)
+        self.wr16(SPR_PAGE, 0)
+        self.wr16(JK_MODE, 0)
+        self.wr16(SCROLL_X, 0)
+        self.wr16(SCROLL_Y, 0)
+        self.wr16(BG_COLOR, 0)
+        self.wr16(SAMPLE_L, 0)
+        self.wr16(SAMPLE_R, 0)
+        self.wr16(SCREENSHOT_Y, 0)
+
+    def dump(self, a, l):
+        """ Dump ``l`` bytes memory starting at address ``a`` """
+        for i in range(0, l, 16):
+            d16 = self.rdstr(a + i, 16)
+            print "%04x  %s" % (a + i, " ".join(["%02x" % ord(c) for c in d16]))
+
+    def wr(self, a, v):
+        """ Write a single byte ``v`` to address ``a``. """
+        self.wrstr(a, chr(v))
+
+    def fill(self, a, v, c):
+        """ Fill ``c`` bytes of memory at address ``a`` with value ``v`` """
+        self.wrstr(a, chr(v) * c)
+
+    def putstr(self, x, y, v):
+        """ Write string ``v`` at screen position (x,y) """
+        a = y * 64 + x
+        self.wrstr(a, v)
+
+    def rd16(self, a):
+        return struct.unpack("<H", self.rdstr(a, 2))[0]
+
+    def rd32(self, a):
+        return struct.unpack("<L", self.rdstr(a, 4))[0]
+
+    def wr16(self, a, v):
+        """ Write 16-bit value ``v`` at to address ``a`` """
+        self.wrstr(a, struct.pack("<H", v))
+
+    def wr32(self, a, v):
+        """ Write 32-bit value ``v`` at to address ``a`` """
+        self.wrstr(a, struct.pack("<L", v))
+
+    def setpal(self, pal, rgb):
+        self.wr16(RAM_PAL + (pal << 1), rgb);
+
+    def ascii(self):
+        stretch = [
+            0x00, 0x03, 0x0c, 0x0f,
+            0x30, 0x33, 0x3c, 0x3f,
+            0xc0, 0xc3, 0xcc, 0xcf,
+            0xf0, 0xf3, 0xfc, 0xff ]
+        gstr = ""
+        for i in range(768):
+          b = ascii_glyphs[i]
+          h = stretch[b >> 4]
+          l = stretch[b & 0xf]
+          gstr += chr(h)
+          gstr += chr(l)
+        self.wrstr(0x1000 + (16 * ord(' ')), gstr)
+        for i in range(0x20, 0x80):
+          self.setpal(4 * i + 0, TRANSPARENT);
+          self.setpal(4 * i + 3, RGB(255,255,255));
+        self.fill(RAM_PIC, ord(' '), 4096);
+
+    def voice(self, v, wave, freq, lamp, ramp = None):
+        """
+        Set the state of a voice.
+
+        :param v: voice number 0-63
+        :type v: int
+        :param wave: wave type, 0 for sine 1 for noise
+        :type wave: int
+        :param freq: frequency control, in quarter-hertz
+        :type freq: int
+        :param lamp: left amplitude 0-255
+        :type lamp: int
+        :param ramp: right amplitude 0-255, defaults to same ``lamp``
+        :type ramp: int
+        """
+        if ramp is None:
+            ramp = lamp
+        self.wr32(VOICES + (4 * v), freq | (wave << 15) | (lamp << 16) | (ramp << 24))
+
+    def silence(self):
+        """ Switch all voices off """
+        for i in range(64):
+            self.voice(i, 0, 4 * 440, 0, 0)
+    
+    def copy(self, a, v):
+        self.wrstr(a, v)
+
+    def microcode(self, src):
+        """
+        Halt coprocessor, load microprogram, restart coprocessor
+
+        :param src: the microprogram, as a string, expressed 
+        :type src: string
+
+        The string is loaded into the Gameduino's microprogram area,
+        and can be up to 256 bytes.  For example, to load the
+        :ref:`splitscreen` microprogram::
+
+            splitscreen_code = open("splitscreen.binle", "b").read()
+            gd.microcode(splitscreen_code)
+
+        """
+
+        self.wr(J1_RESET, 1)
+        self.copy(J1_CODE, src)
+        self.wr(J1_RESET, 0)
+
+    def sprite(self, spr, x, y, image, palette, rot, jk = 0):
+        """
+        Set the state of a hardware sprite
+
+        :param spr: sprite number 0-511
+        :param x: x coordinate
+        :param y: y coordinate
+        :param image: sprite source image 0-63
+        :param palette: sprite palette select, 0-15, see below
+        :param rot: sprite rotate control 0-7, see :ref:`rotate`
+        :param jk: collision class control, 0-1
+
+        Palette select controls the number of colors used for the sprite, the source palette, and which data bits 
+        to use as source.
+
+        """
+
+        self.wr32(RAM_SPR + (4 * spr),
+                  (x & 511) | ((rot & 7) << 9) | ((palette & 15) << 12) | ((y & 511) << 16) | ((image & 63) << 25) | ((jk & 1) << 31))
+
+    def im(self):
+        """
+        Return the current screen as a 400x300 RGB PIL Image::
+
+            >>> import gameduino.sim
+            >>> gd = gameduino.sim.Gameduino()
+            >>> gd.im().save("screenshot.png")
+        """
+        return self._im()

+ 174 - 0
python/gameduino/compress.py

@@ -0,0 +1,174 @@
+import time
+import sys
+import array
+
+def prefix(s1, s2):
+    """ Return the length of the common prefix of s1 and s2 """
+    sz = len(s2)
+    for i in range(sz):
+        if s1[i % len(s1)] != s2[i]:
+            return i
+    return sz
+
+def runlength(blk, p0, p1):
+    """ p0 is the source position, p1 is the dest position
+    Return the length of run of common chars
+    """
+    for i in range(1, len(blk) - p1):
+        if blk[p0:p0+i] != blk[p1:p1+i]:
+            return i - 1
+    return len(blk) - p1 - 1
+
+def runlength2(blk, p0, p1, bsf):
+    """ p0 is the source position, p1 is the dest position
+    Return the length of run of common chars
+    """
+    if blk[p0:p0+bsf+1] != blk[p1:p1+bsf+1]:
+        return 0
+    for i in range(bsf + 1, len(blk) - p1):
+        if blk[p0:p0+i] != blk[p1:p1+i]:
+            return i - 1
+    return len(blk) - p1 - 1
+
+class Bitstream(object):
+    def __init__(self):
+        self.b = []
+    def append(self, sz, v):
+        assert 0 <= v
+        assert v < (1 << sz)
+        for i in range(sz):
+            self.b.append(1 & (v >> (sz - 1 - i)))
+    def toarray(self):
+        bb = [0] * ((len(self.b) + 7) / 8)
+        for i,b in enumerate(self.b):
+            if b:
+                bb[i / 8] |= (1 << (i & 7));
+        return array.array('B', bb)
+
+class Codec(object):
+    def __init__(self, b_off, b_len):
+        self.b_off = b_off
+        self.b_len = b_len
+        self.history = 2 ** b_off
+        refsize = (1 + self.b_off + self.b_len) # bits needed for a backreference
+        if refsize < 9:
+            self.M = 1
+        elif refsize < 18:
+            self.M = 2
+        else:
+            self.M = 3
+        # print "M", self.M
+        # e.g. M 2, b_len 4, so: 0->2, 15->17
+        self.maxlen = self.M + (2**self.b_len) - 1
+
+    def compress(self, blk):
+        lempel = {}
+        sched = []
+        pos = 0
+        while pos < len(blk):
+            k = blk[pos:pos+self.M]
+            older = (pos - self.history - 1)
+            candidates = set([p for p in lempel.get(k, []) if (older < p)])
+            lempel[k] = candidates  # prune old
+            # print pos, repr(k), len(lempel), "lempels", "candidates", len(candidates)
+            def addlempel(c):
+                if c in lempel:
+                    lempel[c].add(pos)
+                else:
+                    lempel[c] = set([pos])
+            if 0:
+                # (bestlen, bestpos) = max([(0, 0)] + [(prefix(blk[p:pos], blk[pos:]), p) for p in candidates])
+                (bestlen, bestpos) = max([(0, 0)] + [(runlength(blk, p, pos), p) for p in candidates])
+                bestlen = min(bestlen, self.maxlen)
+            else:
+                (bestlen, bestpos) = (0, None)
+                for p in candidates:
+                    cl = runlength2(blk, p, pos, bestlen)
+                    if cl > bestlen:
+                        bestlen,bestpos = cl,p
+                    if self.maxlen <= bestlen:
+                        bestlen = min(bestlen, self.maxlen)
+                        break
+            if bestlen >= self.M:
+                sched.append((bestpos - pos, bestlen))
+                for i in range(bestlen):
+                    addlempel(blk[pos:pos+self.M])
+                    pos += 1
+            else:
+                addlempel(k)
+                sched.append(blk[pos])
+                pos += 1
+        return sched
+
+    def toarray(self, blk):
+        sched = self.compress(blk)
+        return self.sched2bs(sched)
+
+    def sched2bs(self, sched):
+        bs = Bitstream()
+        bs.append(4, self.b_off)
+        bs.append(4, self.b_len)
+        bs.append(2, self.M)
+        bs.append(16, len(sched))
+        for c in sched:
+            if len(c) != 1:
+                (offset, l) = c
+                bs.append(1, 1)
+                bs.append(self.b_off, -offset - 1)
+                bs.append(self.b_len, l - self.M)
+            else:
+                bs.append(1, 0)
+                bs.append(8, ord(c))
+        return bs.toarray()
+
+    def to_cfile(self, hh, blk, name):
+        print >>hh, "static PROGMEM prog_uchar %s[] = {" % name
+        bb = self.toarray(blk)
+        for i in range(0, len(bb), 16):
+            if (i & 0xff) == 0:
+                print >>hh
+            for c in bb[i:i+16]:
+                print >>hh, "0x%02x, " % c,
+            print >>hh
+        print >>hh, "};"
+
+    def decompress(self, sched):
+        s = ""
+        for c in sched:
+            if len(c) == 1:
+                s += c
+            else:
+                (offset, l) = c
+                for i in range(l):
+                    s += s[offset]
+        return s
+
+def main():
+    from optparse import OptionParser
+    parser = OptionParser("%prog [ --lookback O ] [ --length L ] --name NAME inputfile outputfile")
+
+    parser.add_option("--lookback", type=int, default=8, dest="O", help="lookback field size in bits")
+    parser.add_option("--length", type=int, default=3, dest="L", help="length field size in bits")
+    parser.add_option("--name", type=str, default="data", dest="NAME", help="name for generated C array")
+    parser.add_option("--binary", action="store_true", default=False, dest="binary", help="write a binary file (default is to write a C++ header file)")
+    options, args = parser.parse_args()
+
+    if len(args) != 2:
+        parser.error("must specify input and output files");
+
+    print options.O
+    print options.L
+    print options.NAME
+    print args
+    (inputfile, outputfile) = args
+    cc = Codec(b_off = options.O, b_len = options.L)
+    uncompressed = open(inputfile, "rb").read()
+    if options.binary:
+        compressed = cc.toarray(uncompressed)
+        open(outputfile, "wb").write(compressed.tostring())
+    else:
+        outfile = open(outputfile, "w")
+        cc.to_cfile(outfile, uncompressed, options.NAME)
+
+if __name__ == "__main__":
+    main()

+ 498 - 0
python/gameduino/prep.py

@@ -0,0 +1,498 @@
+"""
+gameduino.prep - for graphics and sound preparation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The prep module provides utilities for
+preparing Gameduino media: images and sound.
+These utilities can be used, for example, to take image files
+and encode them so that the Gameduino can display them as backgrounds
+or sprites.
+
+
+..
+    This module defines mnemonics for the sprite palette select field:
+    +-----------------------+-------+
+    | PALETTE256A           | 0     |
+    +-----------------------+-------+
+    | PALETTE256B           | 1     |
+    +-----------------------+-------+
+    | PALETTE256C           | 2     |
+    +-----------------------+-------+
+    | PALETTE256D           | 3     |
+    +-----------------------+-------+
+    | PALETTE16A_BITS0123   | 4     |
+    +-----------------------+-------+
+    | PALETTE16A_BITS4567   | 6     |
+    +-----------------------+-------+
+    | PALETTE16B_BITS0123   | 5     |
+    +-----------------------+-------+
+    | PALETTE16B_BITS4567   | 7     |
+    +-----------------------+-------+
+    | PALETTE4A_BITS01      | 8     |
+    +-----------------------+-------+
+    | PALETTE4A_BITS23      | 10    |
+    +-----------------------+-------+
+    | PALETTE4A_BITS45      | 12    |
+    +-----------------------+-------+
+    | PALETTE4A_BITS67      | 14    |
+    +-----------------------+-------+
+    | PALETTE4B_BITS01      | 9     |
+    +-----------------------+-------+
+    | PALETTE4B_BITS23      | 11    |
+    +-----------------------+-------+
+    | PALETTE4B_BITS45      | 13    |
+    +-----------------------+-------+
+    | PALETTE4B_BITS67      | 15    |
+    +-----------------------+-------+
+
+The module defines these constants for use as the ``palset`` argument to  :meth:`ImageRAM.addsprites`:
+
++-------------+-------------------------+
+| PALETTE256A | 256-color palette A     |
++-------------+-------------------------+
+| PALETTE256B | 256-color palette B     |
++-------------+-------------------------+
+| PALETTE256C | 256-color palette C     |
++-------------+-------------------------+
+| PALETTE256D | 256-color palette D     |
++-------------+-------------------------+
+| PALETTE4A   | Four-color palette A    |
++-------------+-------------------------+
+| PALETTE4B   | Four-color palette B    |
++-------------+-------------------------+
+| PALETTE16A  | Sixteen-color palette A |
++-------------+-------------------------+
+| PALETTE16B  | Sixteen-color palette B |
++-------------+-------------------------+
+
+"""
+
+PALETTE256A = [0]
+PALETTE256B = [1]
+PALETTE256C = [2]
+PALETTE256D = [3]
+PALETTE4A_BITS01 = (0x8 + (0 << 1))
+PALETTE4A_BITS23 = (0x8 + (1 << 1))
+PALETTE4A_BITS45 = (0x8 + (2 << 1))
+PALETTE4A_BITS67 = (0x8 + (3 << 1))
+PALETTE4A = (PALETTE4A_BITS01, PALETTE4A_BITS23, PALETTE4A_BITS45, PALETTE4A_BITS67)
+PALETTE4B_BITS01 = (0x8 + (0 << 1) + 1)
+PALETTE4B_BITS23 = (0x8 + (1 << 1) + 1)
+PALETTE4B_BITS45 = (0x8 + (2 << 1) + 1)
+PALETTE4B_BITS67 = (0x8 + (3 << 1) + 1)
+PALETTE4B = (PALETTE4B_BITS01, PALETTE4B_BITS23, PALETTE4B_BITS45, PALETTE4B_BITS67)
+
+PALETTE16A_BITS0123 = (0x4 + (0 << 1))
+PALETTE16A_BITS4567 = (0x4 + (1 << 1))
+PALETTE16A = (PALETTE16A_BITS0123, PALETTE16A_BITS4567)
+PALETTE16B_BITS0123 = (0x4 + (0 << 1) + 1)
+PALETTE16B_BITS4567 = (0x4 + (1 << 1) + 1)
+PALETTE16B = (PALETTE16B_BITS0123, PALETTE16B_BITS4567)
+
+from array import array
+import Image
+
+def dump(hh, name, data):
+    """
+    Writes data to a header file for use in an Arduino Sketch.
+
+    :param hh: destination header file
+    :type hh: :class:`file`
+    :param name: the name of the object, as it will appear in the header file
+    :type name: string
+    :param data: the data to be dumped
+    :type data: :class:`array.array`
+    """
+    print >>hh, "static PROGMEM prog_uchar %s[] = {" % name
+    bb = array('B', data.tostring())
+    for i in range(0, len(bb), 16):
+        if (i & 0xff) == 0:
+            print >>hh
+        for c in bb[i:i+16]:
+            print >>hh, "0x%02x, " % c,
+        print >>hh
+    print >>hh, "};"
+
+def rgbpal(imdata):
+    # For RGBA imdata, return list of (r,g,b) triples and the palette
+    li = array('B', imdata).tolist()
+    rgbas = zip(li[0::4], li[1::4], li[2::4], li[3::4])
+    palette = list(set(rgbas))
+    return (rgbas, palette)
+
+def getch(im, x, y):
+    # return the RGBA data for the 8x8 character at (x, y) in im
+    # if the 8x8 RGB contains more than 4 colors, quantize it using
+    # `scolorq <http://www.cs.berkeley.edu/~dcoetzee/downloads/scolorq/>`_.
+
+    sub88 = im.crop((x, y, x + 8, y + 8))
+    sub88d = sub88.tostring()
+
+    (_, pal) = rgbpal(sub88d)
+    if len(pal) > 4:
+        return sub88.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=4).convert("RGBA")
+    else:
+        return sub88
+
+def rgb555(r, g, b):
+    return ((r / 8) << 10) + ((g / 8) << 5) + (b / 8)
+
+def rgba1555(r, g, b, a):
+    return ((a < 128) << 15) + ((r / 8) << 10) + ((g / 8) << 5) + (b / 8)
+
+def encodech(imdata):
+    """
+    imdata is 8x8x4 RGBA character, string of length 256
+    return the pixel and palette data for it as
+    :class:`array.array` of type 'B' and 'H' respectively.
+    """
+
+    assert len(imdata) == (4 * 8 * 8)
+    (rgbs, palette) = rgbpal(imdata)
+    indices = [palette.index(c) for c in rgbs]
+    indices_b = ""
+    for i in range(0, len(indices), 4):
+        c =   ((indices[i] << 6) +
+               (indices[i + 1] << 4) +
+               (indices[i + 2] << 2) +
+               (indices[i + 3]))
+        indices_b += (chr(c))
+    palette = (palette + ([(0,0,0,255)] * 4))[:4]   # unused palette entries: opaque black
+    ph = array('H', [rgba1555(*p) for p in palette])
+    return (indices_b, ph)
+
+def getpal(im):
+    """ im is a paletted image.  Return its palette as a Gameduino sprite palette
+    in an :class:`array.array` of type 'H'.  This form can be used directly with :func:`dump`::
+
+        import gameduino.prep as gdprep
+        ...
+        gdprep.dump(hfile, "paletteA", gdprep.getpal(im))
+
+    """
+
+    ncol = ord(max(im.tostring())) + 1
+    ncol = min([c for c in [4,16,256] if c >= ncol])
+    lut = im.resize((ncol, 1))
+    lut.putdata(range(ncol))
+    palstr = lut.convert("RGB").tostring()
+    rgbs = zip(*(array('B', palstr[i::3]) for i in range(3)))
+    rgb555 = [(((r / 8) << 10) | ((g / 8) << 5) | (b / 8)) for (r,g,b) in rgbs]
+    if 'transparency' in im.info:
+        rgb555[im.info['transparency']] = 0x8000
+    return array('H', rgb555)
+
+def encode(im):
+    """
+    Convert a PIL image to a Gameduino character background image.
+
+    :param im: A Python Imaging Library image
+    :rtype: tuple of data for (picture, character, font) all :class:`array.array`.
+
+    The image must have dimensions that are multiples of 8.
+    If any character cell contains more than four colors, then the cell's pixel are quantized to four colors before encoding.
+    If the image requires more than 256 unique character cells, this function throws exception OverflowError.
+    The tuple returned contains three pieces of data:
+    
+    * picture - the bytes representing the character cells.  For input image sized (w, h) this array has size (w/8)*(h/8).  Type of this array is 'B' (unsigned byte)
+    * character - the glyphs for all used 8x8 characters.  One character is 16 bytes.  Type of this array is 'B' (unsigned byte)
+    * palette - the 4-color palettes for all used 8x8 characters.  One character is 8 bytes.  Type of this array is 'H' (unsigned short)
+
+    To display the image, load these three arrays into Gameduino memory.  For example,
+    to encode a single image and
+    write its data to a header file ``titlescreen.h``::
+
+      import gameduino.prep as gdprep
+      (dpic, dchr, dpal) = gdprep.encode(Image.open("titlescreen.png"))
+      hdr = open("titlescreen.h", "w")
+      gdprep.dump(hdr, "titlescreen_pic", dpic)
+      gdprep.dump(hdr, "titlescreen_chr", dchr)
+      gdprep.dump(hdr, "titlescreen_pal", dpal)
+
+    and to display the image on the screen, an Arduino sketch might do::
+
+      #include "titlescreen.h"
+
+      void setup()
+      {
+      ...
+        GD.copy(RAM_PIC, titlescreen_pic, sizeof(titlescreen_pic));
+        GD.copy(RAM_CHR, titlescreen_chr, sizeof(titlescreen_chr));
+        GD.copy(RAM_PAL, titlescreen_pal, sizeof(titlescreen_pal));
+
+    """
+
+    if im.mode != "RGBA":
+        im = im.convert("RGBA")
+    charset = {} # dict that maps 8x8 images to byte charcodes
+    picture = [] # 64x64 byte picture RAM
+    for y in range(0, im.size[1], 8):
+        for x in range(0, im.size[0], 8):
+            iglyph = getch(im, x, y)
+            glyph = iglyph.tostring()
+            if not glyph in charset:
+                if len(charset) == 256:
+                    raise OverflowError
+                charset[glyph] = len(charset)
+            picture.append(charset[glyph])
+    picd = array('B', picture)
+    cd = array('B', [0] * 16 * len(charset))
+    pd = array('H', [0] * 4 * len(charset))
+    for d,i in charset.items():
+        for y in range(8):
+            (char, pal) = encodech(d)
+            cd[16 * i:16 * (i+1)] = array('B', char)
+            pd[4 * i:4 * (i+1)] = pal
+    return (picd, cd, pd)
+
+def preview(picd, cd, pd):
+    preview = Image.new("RGB", im.size)
+    preview.paste(iglyph, (x, y))
+    return preview
+
+def glom(sizes):
+    """ Returns a master size and a list of crop/paste coordinates """
+    mw = max(w for (w,h) in sizes)
+    mh = sum(h for (w,h) in sizes)
+    y = 0
+    r = []
+    for (w,h) in sizes:
+        r.append((0, y, w, y + h))
+        y += h
+    return ((mw,mh), r)
+
+
+def palettize(im, ncol):
+    """ Given an input image or list of images, convert to a palettized version using at most ``ncol`` colors.
+    This function preserves transparency: if the input(s) have transparency then the returned
+    image(s) have ``.info['transparency']`` set to the transparent color.
+
+    If ``im`` is a single image, returns a single image.  If ``im`` is a list of images, returns a list of images.
+    """
+    
+    assert ncol in (4, 16, 256)
+    if isinstance(im, list):
+        # For a list of images, paste them all into a single image,
+        # palettize the single image, then return cropped subimages
+
+        for i in im:
+            i.load()
+        (ms, lpos) = glom([i.size for i in im])
+        master = Image.new(im[0].mode, ms)
+        for i,ps in zip(im, lpos):
+            master.paste(i, ps)
+        master = palettize(master, ncol)
+        ims = [master.crop(ps) for ps in lpos]
+        for i in ims:
+            i.info = master.info
+        return ims
+    else:
+        im.load()
+        
+    if im.mode == 'P':
+        if ord(max(im.tostring())) < ncol:
+            return im # already done
+        if 'transparency' in im.info:
+            im = im.convert("RGBA")
+        else:
+            im = im.convert("RGB")
+    assert im.mode in ("RGBA", "RGB")
+    if im.mode == "RGB":
+        return im.convert('P', palette=Image.ADAPTIVE, colors=ncol)
+    else:
+        alpha = im.split()[3]
+        mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0)
+        im.paste((0,0,0), mask)
+        im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors = (ncol - 1))
+        im.paste(ncol - 1, mask)
+        im.info['transparency'] = ncol - 1
+        return im
+
+def isnonblank(im):
+    assert im.mode == 'P'
+    if 'transparency' in im.info:
+        transparent = im.info['transparency']
+        (w,h) = im.size
+        colors = set([im.getpixel((i, j)) for i in range(w) for j in range(h)])
+        return colors != set([transparent])
+    else:
+        return True
+
+class ImageRAM(object):
+    """
+
+    The ImageRAM object simplifies loading of the Gameduino's 16K sprite image RAM.
+    A caller adds sprite images to the ImageRAM, and finally obtains a memory image
+    using :meth:`ImageRAM.used`.
+
+    """
+    def __init__(self, hh):
+        self.hh = hh
+        self.data = array('B', [0] * 16384)
+        self.nxtpage = 0    # next available page
+        self.nxtbit = 0     # next available bit
+
+    def __bump(self, b):
+        self.nxtbit += b
+        if 8 == self.nxtbit:
+            self.nxtbit = 0
+            self.nxtpage += 1
+
+    def add(self, page, size):
+        """
+        Add a sprite image to the ImageRAM
+
+        :param page: image data, a list length 256
+        :param size: size of data elements, either 4, 16 or 256
+        :rtype: Returns a tuple (image, pal)
+
+        This method adds the data in ``page`` to the ImageRAM, and the returns the assigned location.  ``image`` is the
+        sprite image 0-63 containing the data, and ``pal`` is the palette bit select for the data.
+
+        For a 4-color image, ``pal`` is 0-3, for 16-color image ``pal`` is 0-1 and for a 256-color image ``pal`` is 0.
+
+        The ``image`` and ``pal`` values may be used to display the sprite using :cpp:func:`GD::sprite`.
+
+        If the data would cause the ImageRAM to increase beyond 16K, this method throws exception OverflowError.
+        """
+        assert size in (4,16,256)
+        assert max(page) < size, "%d colors allowed, but page contains %d" % (size, max(page))
+        assert len(page) == 256
+
+        bits = {4:2, 16:4, 256:8}[size]
+        while (self.nxtbit % bits) != 0:
+            self.__bump(2)
+        if self.nxtpage == 64:
+            raise OverflowError
+        if size == 4:
+            pal = self.nxtbit / 2
+        elif size == 16:
+            pal = self.nxtbit / 4
+        else:
+            pal = 0
+        pg = self.nxtpage
+        for i in range(256):
+            self.data[256 * self.nxtpage + i] |= (page[i] << self.nxtbit)
+        self.__bump(bits)
+        return (pg, pal)
+
+    def addsprites(self, name, size, im, palset = PALETTE256A, center = (0,0)):
+        """
+        Extract multiple sprite frames from a source image, and generate the code to draw them.
+
+        :param name: name of the sprite set; used to name the generated ``draw_`` function
+        :param size: size of each sprite frame (width, height)
+        :param im: source image, mode must be 'P' - paletted
+        :param palset: palette set to use for the sprite, one of PALETTE256A-D, PALETTE16A-B, PALETTE4A-B
+        :param center: the center pixel of the sprite image.  Default is (0,0) meaning top left pixel.
+
+        Given a sequence of sprite frames in ``im``, this method extracts their data and adds it to the ImageRAM.  
+        In addition, it writes the code to draw the sprite to the ImageRAM's header file.  For example::
+
+            import gameduino.prep as gdprep
+            ir = gdprep.ImageRAM(open("hdr.h", "w"))
+            rock0 = gdprep.palettize(Image.open("rock0r.png"), 16)
+            ir.addsprites("rock0", (16, 16), rock0, gdprep.PALETTE16A, center = (8,8))
+
+        would extract the four 16x16 frames from the ``rock0r.png`` image:
+        
+        .. image:: rock0r.png
+        
+        and write the following code to ``hdr.h``::
+
+            #define ROCK0_FRAMES 4
+            static void draw_rock0(int x, int y, byte anim, byte rot, byte jk = 0) {
+            ...
+            }
+
+        For more more examples, see the :ref:`asteroids` demo game.
+        """
+
+        def get16x16(sheet, x, y):
+            return sheet.crop((16*x, 16*y, 16*(x+1), 16*(y+1)))
+
+        def walktile(im, size):
+            for y in range(0, im.size[1], size[1]):
+                for x in range(0, im.size[0], size[0]):
+                    yield im.crop((x, y, x + size[0], y + size[1]))
+        tiles = list(walktile(im, size))
+
+        print >>self.hh, "#define %s_FRAMES %d" % (name.upper(), len(tiles))
+        animtype = ["byte", "int"][len(tiles) > 255]
+        print >>self.hh, """static void draw_%s(int x, int y, %s anim, byte rot, byte jk = 0) {\n  switch (anim) {""" % (name, animtype)
+        if palset == PALETTE256A:
+            ncolors = 256
+        elif palset == PALETTE256B:
+            ncolors = 256
+        elif palset == PALETTE256C:
+            ncolors = 256
+        elif palset == PALETTE256D:
+            ncolors = 256
+        elif palset == PALETTE4A:
+            ncolors = 4
+        elif palset == PALETTE4B:
+            ncolors = 4
+        elif palset == PALETTE16A:
+            ncolors = 16
+        elif palset == PALETTE16B:
+            ncolors = 16
+        else:
+            highest = ord(max(im.tostring()))
+            ncolors = min([c for c in [4,16,256] if (highest < c)])
+        for spr,spriteimage in enumerate(tiles):
+            loads = []
+            for y in range((size[1] + 15) / 16):
+                for x in range((size[0] + 15) / 16):
+                    t = get16x16(spriteimage, x, y)
+                    t.info = im.info    # workaround: PIL does not copy .info when cropping
+                    if isnonblank(t):
+                        (page, palsel) = self.add(array('B', t.tostring()), ncolors)
+                        loads += ["    GD.xsprite(x, y, %d, %d, %d, %d, rot, jk);" % (x * 16 - center[0], y * 16 - center[1], page, palset[palsel])]
+            if loads:
+                print >>self.hh, "  case %d:" % spr
+                print >>self.hh, "\n".join(loads)
+                print >>self.hh, "    break;"
+
+        print >>self.hh, """  }\n}\n"""
+
+    def used(self):
+        """
+        Return the contents of the ImageRAM, as an :class:`array.array` of type 'B'.
+        The size of the array depends on the amount of data added, up to a limit
+        of 16K.
+        """
+        if self.nxtbit == 0:
+            past = self.nxtpage
+        else:
+            past = self.nxtpage + 1
+        return array('B', self.data[:256*past])
+
+import math
+
+def spectrum(specfile, cutoff = 64, volume = 255):
+    """
+    Read an Audacity spectrum file and return a list of (frequency, amplitude)
+    pairs, loudest first.
+
+    :param cutoff: length of the list of returned pairs
+    :param volume: total volume of the returned pairs
+    :rtype: list of tuples (frequency, amplitude) where frequency is a floating-point frequency in Hz, and amplitude in an integer amplitude.
+
+    This function can be used to create voice profiles for instruments
+    and sounds.  For example to load a choir sound, previously saved
+    as ``choir.txt``::
+        
+        for (i, (f, a)) in enumerate(spectrum("choir.txt")):
+            gd.voice(i, 0, int(4 * f), a, a)
+
+    """
+
+    snd = [[float(t) for t in l.split()] for l in open(specfile) if not "Freq" in l]
+    snd = [(f,db) for (f,db) in snd if 40 < f < 8192]
+    snd = sorted(snd, reverse=True, key=lambda t:t[1])
+    top = snd[:cutoff]
+    amps = [(f,math.pow(2, .1 * db)) for (f, db) in top]
+    samps = sum([a for (f,a) in amps])
+    return [(f, int(volume * a / samps)) for (f, a) in amps]
+
+__all__ = [ "encode", "dump", "palettize", "getpal", "ImageRAM", "spectrum", ]

+ 48 - 0
python/gameduino/registers.py

@@ -0,0 +1,48 @@
+RAM_PIC       = 0x0000    # Screen Picture, 64 x 64 = 4096 bytes
+RAM_CHR       = 0x1000    # Screen Characters, 256 x 16 = 4096 bytes
+RAM_PAL       = 0x2000    # Screen Character Palette, 256 x 8 = 2048 bytes
+
+IDENT         = 0x2800
+REV           = 0x2801
+FRAME         = 0x2802
+VBLANK        = 0x2803
+SCROLL_X      = 0x2804
+SCROLL_Y      = 0x2806
+JK_MODE       = 0x2808
+J1_RESET      = 0x2809
+SPR_DISABLE   = 0x280a
+SPR_PAGE      = 0x280b
+IOMODE        = 0x280c
+
+BG_COLOR      = 0x280e
+SAMPLE_L      = 0x2810
+SAMPLE_R      = 0x2812
+
+SCREENSHOT_Y  = 0x281e
+
+PALETTE16A    = 0x2840    # 16-color palette RAM A, 32 bytes
+PALETTE16B    = 0x2860    # 16-color palette RAM B, 32 bytes
+PALETTE4A     = 0x2880    # 4-color palette RAM A, 8 bytes
+PALETTE4B     = 0x2888    # 4-color palette RAM A, 8 bytes
+COMM          = 0x2890    # Communication buffer
+COLLISION     = 0x2900    # Collision detection RAM, 256 bytes
+VOICES        = 0x2a00    # Voice controls
+J1_CODE       = 0x2b00    # J1 coprocessor microcode RAM
+SCREENSHOT    = 0x2c00    # screenshot line RAM
+
+RAM_SPR       = 0x3000    # Sprite Control, 512 x 4 = 2048 bytes
+RAM_SPRPAL    = 0x3800    # Sprite Palettes, 4 x 256 = 2048 bytes
+RAM_SPRIMG    = 0x4000    # Sprite Image, 64 x 256 = 16384 bytes
+
+def RGB(r, g, b):
+    """ Return the 16-bit hardware encoding of color (R,G,B).
+
+    :param R: red value 0-255
+    :param G: green value 0-255
+    :param B: blue value 0-255
+    :rtype: int
+    """
+    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)
+
+TRANSPARENT = (1 << 15)
+

+ 130 - 0
python/gameduino/remote.py

@@ -0,0 +1,130 @@
+"""
+gameduino.remote - remote interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The remote interface lets Python scripts read and write
+Gameduino memory, via the USB connection and a
+simple client running on the Arduino.
+
+The remote interface can be more convenient than compiling and uploading a
+Sketch when developing media and coprocessor microprograms::
+
+    import gameduino.remote
+    gd = gameduino.remote.Gameduino("/dev/ttyUSB0", 115200)
+    gd.ascii()
+    gd.putstr(0, 5, "Hello from Python")
+
+The Gameduino in this module is similar to the one in :mod:`gameduino.sim`.
+
+Because this module uses USB serial interface to communicate with the Arduino,
+it requires the `PySerial module <http://pyserial.sourceforge.net/>`_.
+
+.. image:: remote.png
+
+The Arduino runs a simple program ``memloader`` that
+listens for serial commands and accesses Gameduino memory.
+"""
+
+import struct
+import serial
+import time
+import array
+
+from gameduino.registers import *
+from gameduino.base import BaseGameduino
+
+class Gameduino(BaseGameduino):
+
+    def __init__(self, usbport, speed):
+        self.ser = serial.Serial(usbport, speed)
+        time.sleep(2)
+        assert self.rd(IDENT) == 0x6d, "Missing IDENT"
+        self.mem = array.array('B', [0] * 32768)
+        self.coldstart()
+
+    def wrstr(self, a, s):
+        if not isinstance(s, str):
+            s = s.tostring()
+        self.mem[a:a+len(s)] = array.array('B', s)
+        for i in range(0, len(s), 255):
+            sub = s[i:i+255]
+            ff = struct.pack(">BH", len(sub), 0x8000 | (a + i)) + sub
+            self.ser.write(ff)
+
+    def rd(self, a):
+        """ Read byte at address ``a`` """
+        ff = struct.pack(">BH", 1, a)
+        self.ser.write(ff)
+        return ord(self.ser.read(1))
+
+    def rdstr(self, a, n):
+        """
+        Read ``n`` bytes starting at address ``a``
+
+        :rtype: string of length ``n``.
+        """
+        r = ""
+        while n:
+            cnt = min(255, n)
+            ff = struct.pack(">BH", cnt, a)
+            self.ser.write(ff)
+            r += self.ser.read(cnt)
+            a += cnt
+            n -= cnt
+        return r
+
+    def waitvblank(self):
+        while self.rd(VBLANK) == 1:
+            pass
+        while self.rd(VBLANK) == 0:
+            pass
+
+    def linecrc(self, y):
+        self.ser.write(struct.pack(">BBH", 0, ord('L'), y))
+        return struct.unpack(">L", self.ser.read(4))[0]
+
+    def coll(self):
+        """
+        Return the 256 bytes of COLLISION RAM.
+
+        :rtype: list of byte values.
+        """
+        self.ser.write(struct.pack(">BB", 0, ord('c')))
+        return array.array('B', self.ser.read(256)).tolist()
+
+    def collcrc(self):
+        self.ser.write(struct.pack(">BB", 0, ord('C')))
+        return struct.unpack(">L", self.ser.read(4))[0]
+
+    def memcrc(self, a, s):
+        self.ser.write(struct.pack(">BBHH", 0, ord('M'), a, s))
+        return struct.unpack(">L", self.ser.read(4))[0]
+
+    def _im(self):
+        """
+        Return the current screen as a 400x300 RGB PIL Image::
+
+            >>> import gameduino.sim
+            >>> gd = gameduino.sim.Gameduino()
+            >>> gd.im().save("screenshot.png")
+        """
+        import Image
+        fi = Image.new("RGB", (400,300))
+        for y in range(300):
+            self.wr16(SCREENSHOT_Y, 0x8000 | y)
+            while (self.rd16(SCREENSHOT_Y) & 0x8000) == 0:
+                pass
+            ld = array.array('H', self.rdstr(SCREENSHOT, 800))
+            r = [8 * (31 & (v >> 10)) for v in ld]
+            g = [8 * (31 & (v >> 5)) for v in ld]
+            b = [8 * (31 & (v >> 0)) for v in ld]
+            rgb = sum(zip(r,g,b), ())
+            li = Image.fromstring("RGB", (400,1), array.array('B', rgb).tostring())
+            fi.paste(li, (0, y))
+        self.wr16(SCREENSHOT_Y, 0)
+        return fi
+
+
+import array
+def readarray(filename):
+    return array.array('B', open(filename).read())

+ 274 - 0
python/gameduino/sim.py

@@ -0,0 +1,274 @@
+"""
+gameduino.sim - simple simulator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Gameduino simulator can simulate some aspects of Gameduino hardware, both video and audio.
+It can be a useful tool for previewing media before loading on actual hardware.
+
+The Gameduino in this module is similar to the one in :mod:`gameduino.remote`::
+
+    import gameduino
+    import gameduino.prep as gdprep
+    import gameduino.sim as gdsim
+
+    im = Image.open("platformer.png").convert("RGB")
+    (picd,chrd,pald) = gdprep.encode(im)
+    gd = gdsim.Gameduino()
+    gd.wrstr(gameduino.RAM_PIC, picd)
+    gd.wrstr(gameduino.RAM_CHR, chrd)
+    gd.wrstr(gameduino.RAM_PAL, pald)
+    gd.im().save("preview.png")
+
+The simulator can produce screenshots (:meth:`Gameduino.im`), generate
+single-note sounds (:meth:`Gameduino.writewave`), and simulate collision RAM
+(:meth:`Gameduino.coll`).  It does not currently simulate the coprocessor.
+
+"""
+
+import struct
+import time
+import array
+import math
+import itertools
+import wave
+import binascii
+
+import Image
+
+from gameduino.registers import *
+from gameduino.base import BaseGameduino
+
+def sum512(a, b):
+    return 511 & (a + b)
+def s9(vv):
+    vv &= 0x1ff
+    if vv > 400:
+        vv -= 512;
+    return vv
+        
+class Gameduino(BaseGameduino):
+    """
+    The Gameduino object simulates some aspects of the Gameduino hardware.  For example::
+
+        >>> import gameduino
+        >>> import gameduino.sim as gdsim
+        >>> gd = gdsim.Gameduino()
+        >>> print hex(gd.rd(gameduino.IDENT))
+        0x6d
+    """
+
+    def __init__(self):
+        self.mem = array.array('B', [0] * 32768)
+        self.mem[IDENT] = 0x6d
+        self.coldstart()
+
+    def wrstr(self, a, s):
+        if not isinstance(s, str):
+            s = s.tostring()
+        self.mem[a:a+len(s)] = array.array('B', s)
+
+    def rd(self, a):
+        """ Read byte at address ``a`` """
+        return self.mem[a]
+
+    def rdstr(self, a, n):
+        """
+        Read ``n`` bytes starting at address ``a``
+
+        :rtype: string of length ``n``.
+        """
+        return self.mem[a:a+n].tostring()
+
+    def writewave(self, duration, dst):
+        """
+        Write the simulated output of the sound system to a wave file
+
+        :param duration: length of clip in seconds
+        :param dst: destination wave filename
+        """
+        sintab = [int(127 * math.sin(2 * math.pi * i / 128.)) for i in range(128)]
+        nsamples = int(8000 * duration)
+        master = [i/8000. for i in range(nsamples)]
+        lacc = [0] * nsamples
+        racc = [0] * nsamples
+        for v in range(64):
+            if v == self.rd(RING_START):
+                print v, max(lacc)
+                ring = [s/256 for s in lacc]
+                lacc = [0] * nsamples
+                racc = [0] * nsamples
+
+            (freq,la,ra) = struct.unpack("<HBB", self.rdstr(VOICES + 4 * v, 4))
+            if la or ra:
+                tone = [sintab[int(m * freq * 32) & 0x7f] for m in master]
+                if self.rd(RING_START) <= v < self.rd(RING_END):
+                    lacc = [o + la * (r * t) / 256 for (o,r,t) in zip(lacc, ring, tone)]
+                    racc = [o + ra * (r * t) / 256 for (o,r,t) in zip(racc, ring, tone)]
+                else:
+                    lacc = [o + la * t for (o,t) in zip(lacc, tone)]
+                    racc = [o + ra * t for (o,t) in zip(racc, tone)]
+        merged = [None,None] * nsamples
+        merged[0::2] = lacc
+        merged[1::2] = racc
+        raw = array.array('h', merged)
+        w = wave.open(dst, "wb")
+        w.setnchannels(2)
+        w.setsampwidth(2)
+        w.setframerate(8000)
+        w.writeframesraw(raw)
+        w.close()
+
+    def bg(self, lines = range(512)):
+        bg_color = self.rd16(BG_COLOR) & 0x7fff
+        glyphs = []
+        for i in range(256):
+            pals = array.array('H', self.mem[RAM_PAL + 8 * i:RAM_PAL + 8 * i + 8].tostring())
+            for j in range(4):
+                if pals[j] & 0x8000:
+                    pals[j] = bg_color
+            glyph = []
+            for y in range(8):
+                for x in range(8):
+                    pix = 3 & (self.mem[RAM_CHR + 16 * i + 2 * y + (x / 4)] >> [6,4,2,0][x&3])
+                    glyph.append(pals[pix])
+            glyphs.append(glyph)
+        img = {}
+        for y in lines:
+            line = []
+            for x in range(512):
+                c = self.mem[RAM_PIC + 64 * (y >> 3) + (x >> 3)]
+                line.append(glyphs[c][8 * (y & 7) + (x & 7)])
+            img[y] = line
+        return img
+
+    def sprfetch(self, img, pal, rot, x, y):
+        if rot & 1:
+            exo,eyo = y,x
+        else:
+            exo,eyo = x,y
+        if rot & 2:
+            exo = 15 - exo
+        if rot & 4:
+            eyo = 15 - eyo
+        ix = self.rd(RAM_SPRIMG + 256 * img + 16 * eyo + exo)
+        if (pal & 0xc) == 0:
+            pix = self.rd16(RAM_SPRPAL + 512 * (pal & 3) + 2 * ix)
+        elif (pal & 0xc) == 4:
+            nyb = 15 & (ix >> [0,4][1 & (pal >> 1)])
+            pix = self.rd16(PALETTE16A + 32 * (pal & 1) + 2 * nyb)
+        else:
+            nyb = 3 & (ix >> [0,2,4,6][3 & (pal >> 1)])
+            pix = self.rd16(PALETTE4A + 8 * (pal & 1) + 2 * nyb)
+        return pix
+
+    def spr_page(self):
+        return RAM_SPR + 1024 * (self.rd(SPR_PAGE) & 1)
+
+    def sp(self, y, line):
+        if self.rd(SPR_DISABLE) & 1:
+            return line
+        page = self.spr_page()
+        for i in range(256):
+            sprval = self.rd32(page + 4 * i)
+            sx = s9(sprval)
+            sy = s9(sprval >> 16)
+            simg = (sprval >> 25) & 63
+            spal = (sprval >> 12) & 15
+            srot = (sprval >> 9) & 7
+            yo = y - sy
+            if 0 <= yo < 16:
+                for xo in range(16):
+                    if 0 <= (sx + xo) < 400:
+                        pix = self.sprfetch(simg, spal, srot, xo, yo)
+                        if pix < 32768:
+                            line[sx + xo] = pix
+        return line
+    def coll(self):
+        """
+        Return the 256 bytes of COLLISION RAM.
+
+        :rtype: list of byte values.
+        """
+        coll = 256 * [0xff]
+        page = self.spr_page()
+        jkmode = (self.rd(JK_MODE) & 1) != 0
+        if 0 == (self.rd(SPR_DISABLE) & 1):
+            yocc = [[] for i in range(300)]
+            for i in range(256):
+                sprval = self.rd32(page + 4 * i)
+                sy = s9(sprval >> 16)
+                for j in range(16):
+                    if 0 <= (sy + j) < 300:
+                        yocc[sy + j].append(i)
+            for y in range(300):
+                tag = [None] * 400
+                jk = [None] * 400
+                for i in yocc[y]:
+                    sprval = self.rd32(page + 4 * i)
+                    sy = s9(sprval >> 16)
+                    yo = y - sy
+                    if 0 <= yo < 16:
+                        sx = s9(sprval)
+                        simg = (sprval >> 25) & 63
+                        spal = (sprval >> 12) & 15
+                        srot = (sprval >> 9) & 7
+                        sjk = (sprval >> 31)
+                        for xo in range(16):
+                            x = sx + xo
+                            if 0 <= x < 400:
+                                if self.sprfetch(simg, spal, srot, xo, yo) < 32768:
+                                    if tag[x] != None:
+                                        if (not jkmode) or (jk[x] != sjk):
+                                            coll[i] = tag[x]
+                                    tag[x] = i
+                                    jk[x] = sjk
+        return coll
+
+    def screen(self, lines, w = 400):
+        sx = self.rd16(SCROLL_X) & 511
+        sy = self.rd16(SCROLL_Y)
+        bg = self.bg([sum512(y, sy) for y in lines])
+        def wrapx(l):
+            return (l + l)[sx:sx+w]
+        return dict([(y, self.sp(y, wrapx(bg[sum512(y, sy)]))) for y in lines])
+
+    def _im(self):
+        return self._imwh(400, 300)
+
+    def fullim(self):
+        """ Return the entire 512x512 pixel screen image """
+        return _imwh(512, 512)
+
+    def _imwh(self, w, h):
+        import Image
+        fi = Image.new("RGB", (w, h))
+        lines = self.screen(range(h), w)
+        for y in range(h):
+            ld = lines[y]
+            r = [8 * (31 & (v >> 10)) for v in ld]
+            g = [8 * (31 & (v >> 5)) for v in ld]
+            b = [8 * (31 & (v >> 0)) for v in ld]
+            rgb = sum(zip(r,g,b), ())
+            li = Image.fromstring("RGB", (w,1), array.array('B', rgb).tostring())
+            fi.paste(li, (0, y))
+        return fi
+
+    def linecrc(self, y):
+        line = array.array('H', self.screen([y])[y]).tostring()
+        return 0xffffffff & binascii.crc32(line)
+
+    def collcrc(self):
+        return 0xffffffff & binascii.crc32(array.array('B', self.coll()).tostring())
+
+    def memcrc(self, a, s):
+        return 0xffffffff & binascii.crc32(self.mem[a:a+s])
+
+    def memory(self):
+        """ Returns current image of memory as a 32768 byte string """
+        return self.mem.tostring()
+
+def readarray(filename):
+    return array.array('B', open(filename).read())
+
+
+__all__ = [ "Gameduino" ]

+ 4 - 0
python/go

@@ -0,0 +1,4 @@
+sudo python setup.py install || exit
+# python remoteunit.py /dev/ttyUSB0 ; exit
+python unit.py TestGameduino.test_471fcf9e || exit
+# python randoms.py /dev/ttyUSB0

BIN
python/platformer.png


+ 190 - 0
python/randoms.py

@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+
+import sys
+import time
+import math
+import array
+import random
+
+import gameduino
+import gameduino.remote
+import gameduino.sim
+
+from duplicator import Duplicator
+
+random.seed(10)
+
+def read_y(y):
+    gd.wr16(gameduino.SCREENSHOT_Y, 0x8000 | y)
+    gd.waitvblank()
+    gd.waitvblank()
+    line = "".join([gd.rdstr(gameduino.SCREENSHOT + i, 200) for i in range(0, 800, 200)])
+    gd.wr16(gameduino.SCREENSHOT_Y, 0)
+    return array.array('H', line).tolist()
+
+def sling(n):
+    n1s = random.randrange(n + 1)
+    return sum([(1 << i) for i in random.sample(range(n), n1s)])
+
+def r(n):
+    return random.randrange(n)
+
+def randbytes(n):
+    return array.array('B', [r(256) for i in range(n)])
+
+def matches(r):
+    return r[0] == r[1]
+
+class TestRegime(object):
+    def __init__(self, dd):
+        self.dd = dd
+        assert matches(dd.rd(gameduino.IDENT))
+        self.dd.microcode(open("../synth/sketches/j1firmware/thrasher.binle").read())
+        self.setup()
+
+    def scramble(self):
+        """ Scramble all registers and memories """
+        for rg in self.reg8s:
+            self.dd.wr(rg, r(2**8))
+        for rg in self.reg16s:
+            self.dd.wr16(rg, r(2**16))
+        for a,s in self.memories:
+            self.dd.wrstr(a, randbytes(s))
+
+    def setup(self):
+        self.scramble()
+
+    def cycle(self):
+        for c in xrange(1000000):
+            print "Cycle", c
+            for (area,size) in random.sample(self.memories, r(len(self.memories))):
+                dat = randbytes(1 + sling(6))
+                if len(dat) == size:
+                    a = area
+                else:
+                    a = area + random.randrange(0, size - len(dat))
+                self.dd.wrstr(a, dat)
+            if r(2) == 0 and self.reg16s:
+                self.dd.wr16(random.choice(self.reg16s), random.getrandbits(16))
+            if r(2) == 0 and self.reg8s:
+                self.dd.wr(random.choice(self.reg8s), random.getrandbits(8))
+
+            for (y, (e,a)) in [(y, self.dd.linecrc(y)) for y in self.checklines()]:
+                if e != a:
+                    print "mismatch at line", y, (e,a)
+                    e = gameduino.sim.screen([y])[y]
+                    a = read_y(y)
+                    print "expected", e
+                    print "actual", a
+                    print set([(ee != aa) for (ee,aa) in zip(e,a)])
+                    print 'y', self.dd.linecrc(y)
+                    sys.exit(1)
+            a,s = random.choice(self.memories)
+            if r(5) == 0:
+                assert matches(self.dd.rd(a + r(s)))
+            if r(5) == 0:
+                assert matches(self.dd.memcrc(a, s))
+
+            if not matches(self.dd.collcrc()):
+                def s9(vv):
+                    vv &= 0x1ff
+                    if vv > 400:
+                        vv -= 512;
+                    return vv
+
+                if 0:
+                    page = self.dd.spr_page()[0]
+                    for i in range(256):
+                        sprval = gdsim.rd32(page + 4 * i)
+                        sx = s9(sprval)
+                        sy = s9(sprval >> 16)
+                        simg = (sprval >> 25) & 63
+                        spal = (sprval >> 12) & 15
+                        srot = (sprval >> 9) & 7
+                        sjk = (sprval >> 31)
+                        print "%3d: x=%3d y=%3d img=%2d pal=%d rot=%d jk=%d" % (i, sx, sy, simg, spal, srot, sjk)
+                (e,a) = self.dd.coll()
+                print 'collcrc', self.dd.collcrc()
+                import binascii
+                print 'e crc', 0xffffffff & binascii.crc32(array.array('B', e).tostring())
+                print 'a crc', 0xffffffff & binascii.crc32(array.array('B', a).tostring())
+                for i in range(256):
+                    print "%3d: e=%3d a=%3d" % (i, e[i], a[i])
+                sys.exit(1)
+            # gdsim.im().save("p%04d.png" % c)
+
+class FullchipRegime(TestRegime):
+    reg16s = [gameduino.SCROLL_X, gameduino.SCROLL_Y, gameduino.BG_COLOR, gameduino.SAMPLE_L, gameduino.SAMPLE_R]
+    reg8s = [gameduino.IDENT,
+             gameduino.REV,
+             gameduino.SPR_PAGE,
+             gameduino.JK_MODE,
+             gameduino.SPR_DISABLE,
+             gameduino.IOMODE]
+    memories = [
+                (gameduino.RAM_PIC, 10 * 1024),
+                (gameduino.RAM_SPR, 2048),
+                (gameduino.RAM_SPRPAL, 2048),
+                (gameduino.RAM_SPRIMG, 16384),
+                (gameduino.PALETTE16A, 64),
+                (gameduino.PALETTE4A, 64),
+                (gameduino.VOICES, 256),
+                # (gameduino.IDENT, 64), # register file
+                ]
+    def checklines(self):
+        return [0, 299] + random.sample(range(1, 299), 2)
+
+class SpriteRegime(TestRegime):
+    reg16s = []
+    reg8s = [gameduino.JK_MODE,
+             gameduino.SPR_PAGE]
+    memories = [
+                (gameduino.RAM_SPR, 2048),
+                (gameduino.RAM_SPRPAL, 2048),
+                # (gameduino.RAM_SPRIMG, 16384),
+                (gameduino.PALETTE16A, 64),
+                (gameduino.PALETTE4A, 64),
+                (gameduino.VOICES, 256),
+                ]
+
+    def setup(self):
+        self.scramble()
+        patt = (
+            "0101010101010101"
+            "1222222222222220"
+            "0222222222222221"
+            "1222222222222220"
+            "0222222222222221"
+            "1222222222222220"
+            "0222222222222221"
+            "1222222222222220"
+            "0222222222222221"
+            "1222222222222220"
+            "0222222222222221"
+            "1222222222222220"
+            "0222222222222221"
+            "1222222222222220"
+            "0222222222222221"
+            "1010101010101010" )
+        def expand(c):
+            c = int(c)
+            return c + 4 * c + 16 * c + 64 * c
+
+        image = array.array('B', [expand(c) for c in patt])
+        for i in range(64):
+            self.dd.wrstr(gameduino.RAM_SPRIMG + 256 * i, image);
+        self.dd.microcode(open("../synth/sketches/j1firmware/thrasher.binle").read())
+
+    def checklines(self):
+        return []
+
+def main():
+    gdsim = gameduino.sim.Gameduino()
+    gd = gameduino.remote.Gameduino(sys.argv[1], 115200)
+    dd = Duplicator((gdsim, gd))
+    # rr = SpriteRegime(dd)
+    rr = FullchipRegime(dd)
+    rr.cycle()
+
+if __name__ == '__main__':
+    main()

Some files were not shown because too many files changed in this diff