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

This commit is contained in:
Godzil 2017-05-31 12:44:42 +01:00
parent 2b0c1e60f3
commit f622dafc8a
107 changed files with 12183 additions and 0 deletions

View File

@ -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) [![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 Licensing
--------- ---------

Binary file not shown.

BIN
archives/Gameduino_b0.zip Normal file

Binary file not shown.

BIN
archives/Gameduino_b0m.zip Normal file

Binary file not shown.

BIN
archives/Gameduino_b1m.zip Normal file

Binary file not shown.

BIN
archives/Gameduino_b2m.zip Normal file

Binary file not shown.

BIN
archives/Gameduino_b3m.zip Normal file

Binary file not shown.

BIN
archives/Gameduino_m.zip Normal file

Binary file not shown.

6
archives/README.md Normal file
View File

@ -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

Binary file not shown.

61
j0/firmware/basewords.fs Normal file
View File

@ -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
j0/firmware/bgstripes.fs Normal file
View File

@ -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
j0/firmware/cold.fs Normal file
View File

@ -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
j0/firmware/crossj1.fs Normal file
View File

@ -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
j0/firmware/dna.fs Normal file
View File

@ -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
j0/firmware/eforth.fs Normal file
View File

@ -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
j0/firmware/eraser.fs Normal file
View File

@ -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
j0/firmware/flowtest.fs Normal file
View File

@ -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
j0/firmware/helloworld.fs Normal file
View File

@ -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
j0/firmware/hwdefs.fs Normal file
View File

@ -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
j0/firmware/main.fs Normal file
View File

@ -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
j0/firmware/memtest.fs Normal file
View File

@ -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
j0/firmware/nuc.fs Normal file
View File

@ -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
j0/firmware/palcopy.fs Normal file
View File

@ -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
j0/firmware/random.fs Normal file
View File

@ -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

View File

@ -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

View File

@ -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
j0/firmware/reload.fs Normal file
View File

@ -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
j0/firmware/screens.fs Normal file
View File

@ -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
j0/firmware/selftest1.fs Normal file
View File

@ -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
j0/firmware/setpixel.fs Normal file
View File

@ -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
j0/firmware/showvoices.fs Normal file
View File

@ -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

View File

@ -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
j0/firmware/spectrum.fs Normal file
View File

@ -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

View File

@ -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
j0/firmware/spr512.fs Normal file
View File

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

42
j0/firmware/testflash.fs Normal file
View File

@ -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
j0/firmware/wireframe.fs Normal file
View File

@ -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
j1/firmware/Makefile Normal file
View File

@ -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
j1/firmware/ans.fs Normal file
View File

@ -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
j1/firmware/arp.fs Normal file
View File

@ -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
j1/firmware/basewords.fs Normal file
View File

@ -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
j1/firmware/clock.fs Normal file
View File

@ -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
j1/firmware/crossj1.fs Normal file
View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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

View File

@ -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
j1/firmware/dhcp.fs Normal file
View File

@ -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
j1/firmware/dns.fs Normal file
View File

@ -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
j1/firmware/doc.fs Normal file
View File

@ -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
j1/firmware/document.fs Normal file
View File

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

28
j1/firmware/encode.py Normal file
View File

@ -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
j1/firmware/eth-ax88796.fs Normal file
View File

@ -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 Normal file

Binary file not shown.

BIN
j1/firmware/fsm-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

11
j1/firmware/genoffsets.py Normal file
View File

@ -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
j1/firmware/go Normal file
View File

@ -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
j1/firmware/hwdefs.fs Normal file
View File

@ -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
j1/firmware/intelhex.py Normal file
View File

@ -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
j1/firmware/invaders.fs Normal file
View File

@ -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
j1/firmware/ip.fs Normal file
View File

@ -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
j1/firmware/ip0.fs Normal file
View File

@ -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 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

28
j1/firmware/keycodes.fs Normal file
View File

@ -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
j1/firmware/loader.fs Normal file
View File

@ -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
j1/firmware/main.fs Normal file
View File

@ -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
j1/firmware/mkblob.py Normal file
View File

@ -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
j1/firmware/ntp.fs Normal file
View File

@ -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
j1/firmware/nuc.fs Normal file
View File

@ -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
j1/firmware/packet.fs Normal file
View File

@ -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
j1/firmware/ps2kb.fs Normal file
View File

@ -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
j1/firmware/sincos.fs Normal file
View File

@ -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
j1/firmware/sprite.fs Normal file
View File

@ -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
j1/firmware/tftp.fs Normal file
View File

@ -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
j1/firmware/time.fs Normal file
View File

@ -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
j1/firmware/twist.py Normal file
View File

@ -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
j1/firmware/udp.fs Normal file
View File

@ -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
j1/firmware/version.fs Normal file
View File

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

9
j1/synth/Makefile Normal file
View File

@ -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
j1/synth/j1.bmm Normal file
View File

@ -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
j1/synth/j1.ucf Normal file
View File

@ -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
j1/synth/xilinx.mk Normal file
View File

@ -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
j1/synth/xilinx.opt Normal file
View File

@ -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
j1/verilog/ck_div.v Normal file
View File

@ -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
j1/verilog/j1.v Normal file
View File

@ -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
j1/verilog/rams.v Normal file
View File

@ -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
j1/verilog/top.v Normal file
View File

@ -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 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

8
python/duplicator.py Normal file
View File

@ -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

View File

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

207
python/gameduino/base.py Normal file
View File

@ -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()

View File

@ -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
python/gameduino/prep.py Normal file
View File

@ -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", ]

View File

@ -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
python/gameduino/remote.py Normal file
View File

@ -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
python/gameduino/sim.py Normal file
View File

@ -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
python/go Normal file
View File

@ -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 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

190
python/randoms.py Normal file
View File

@ -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 have changed in this diff Show More