diff --git a/pico-ice/ice40/flyclasses.fs b/pico-ice/ice40/flyclasses.fs new file mode 100644 index 0000000..5324da2 --- /dev/null +++ b/pico-ice/ice40/flyclasses.fs @@ -0,0 +1,44 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +vocabulary flyclasses flyclasses definitions + +0 value classes +1 value methods +0 value dispatch +0 value implementing + +: flyclass create classes , 1 +to classes does> @ ; +: method& ( m cls -- a ) classes mod methods * + cells dispatch + ; +: accrued ( -- a ) 0 implementing method& ; +: method create methods , 1 +to methods does> @ over method& @ execute ; +: implementation ( cls -- ) to implementing ; +: >min ( a -- n ) cell+ @ ; : >max ( a -- a ) @ ; +: >below ( a -- a ) 2 cells + @ ; : >above ( a -- a) 3 cells + @ ; +: field ( min max -- "name" ) + create 2dup , , accrued @ , swap - 1+ accrued @ * dup , accrued ! + does> >r r@ >above mod r@ >below / r> >min + ; +: doput ( n o -- o "name" ) >r dup r@ >below mod swap r@ >above / r@ >above * + + swap r@ >max min r@ >min - r> >below * + ; +: put ( n o -- o "name" ) ' >body postpone literal postpone doput ; immediate +: extension ( cls -- ) 0 swap method& accrued methods cells cmove ; +: initiate here to dispatch + classes 1- for classes , methods 1- 1- for ['] abort , next next ; +: do:: ( o cls m -- ) swap method& @ execute ; +: :: ( o cls "name" -- ) ' >body @ postpone literal postpone do:: ; immediate +: m: ' >body @ :noname ; +: ;m postpone ; swap implementing method& ! ; immediate + +forth definitions + diff --git a/pico-ice/ice40/ice40.fs b/pico-ice/ice40/ice40.fs new file mode 100644 index 0000000..7da18b6 --- /dev/null +++ b/pico-ice/ice40/ice40.fs @@ -0,0 +1,16 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +needs ice40_synthesis.fs +needs ice40_storage.fs diff --git a/pico-ice/ice40/ice40_allocation.fs b/pico-ice/ice40/ice40_allocation.fs new file mode 100644 index 0000000..f99ff2e --- /dev/null +++ b/pico-ice/ice40/ice40_allocation.fs @@ -0,0 +1,72 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +needs ice40_layout.fs + +ice40 synthesis definitions + +1 value tx +1 value ty +0 value tb + +: PLACE ( x y -- ) to ty to tx 0 to tb ; +: PLACE-OUTPUT ( -- o ) tx ty tb Output .create ; +: USED? ( -- f ) place-output .isLogic? 0= if -1 exit then + place-output .getLogic 0<> ; + +: ADVANCE + tb 7 < if 1 +to tb exit then + ty cells-height 1- < if 1 +to ty 0 to tb exit then + tx cells-width 1- < assert + 1 +to tx 0 to ty 0 to tb +; + +: allot-lut ( -- o ) + begin used? while + advance + repeat + place-output +; + +: ROUTE! { src dst -- } + src dst route 0= if + ." ERROR UNABLE TO ROUTE!!!" cr + ." SOURCE: " src .print cr + ." DESTINATION: " dst .print cr + 123 throw + then + src dst route. +; + +: LUT4 { i0 i1 i2 i3 tbl -- o } + allot-lut { o } + tbl o .setLogic + i0 0 o .getInput route! + i1 1 o .getInput route! + i2 2 o .getInput route! + i3 3 o .getInput route! + o +; + +: FFL ( -- o ) + allot-lut { o } + $aaaa o .setLogic + -1 o .dffEnableBit .setBit + o +; + +: FF! ( v ff -- ) 0 swap .getInput route! ; + +forth definitions + diff --git a/pico-ice/ice40/ice40_config.fs b/pico-ice/ice40/ice40_config.fs new file mode 100644 index 0000000..de78314 --- /dev/null +++ b/pico-ice/ice40/ice40_config.fs @@ -0,0 +1,65 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +vocabulary ice40 ice40 definitions + +( For the 5k model in the pico-ice ) + +26 constant cells-width +32 constant cells-height +6 constant bram-column1 +19 constant bram-column2 + +692 constant cram-bank-width +336 constant cram-height-lower +176 constant cram-height-upper +cram-height-lower cram-height-upper + constant cram-height +cram-bank-width 2* cram-height * 8 / constant cram-size + +160 constant bram-width-lower +80 constant bram-width-upper +256 constant bram-bank-height +128 constant bram-chunk-size + +( For the SG48 package in the pico-ice ) +48 constant pinmax pinmax 1+ 2* cells constant pinsize +create pinmap pinsize allot pinmap pinsize 0 fill +0 value pinpos : x 1 +to pinpos ; : p ( p# -- ) pinpos swap cells pinmap + ! x ; +: pin#s ( p# -- x y b ) cells pinmap + @ 24 /mod >r 1+ r> 2 /mod 1 xor 31 * swap ; +\ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 COLUMN +\ | | | | | | | | | | | | | | | | | | | | | | | | + x x x 39 p 40 p 41 p x 42 p 43 p x x x 37 p x x 32 p 28 p 26 p 23 p x x x x x \ 0 TOP + x x x x x x x 38 p 36 p x x 35 p 34 p x x 31 p x 27 p 25 p x x x x x \ 1 +\ | | | | | | | | | | | | | | | | | | | | | | | | PIN# + x x x x 46 p 47 p 48 p 2 p 4 p x x x x x 9 p 10 p 11 p 12 p 13 p x x x 14 p 15 p \ 0 + x x x x x 44 p 45 p x 3 p x x x 6 p x x x x 21 p 20 p x 19 p 18 p 17 p 16 p \ 1 BOT + +( Whole bitmap for config ram ) +cram-size allocate throw constant cram +cram cram-size 0 fill + +( Clear, read, and write as a bitmap ) +: clear cram cram-size 0 fill ; +: cr& ( x y -- a*8 ) cram-height-lower /mod if + cram-height-upper 1- swap - cram-height-lower + + then cram-bank-width * >r + cram-bank-width 2 - /mod if + cram-bank-width 1- swap - 2 - cram-bank-width cram-height * + + then r> + ; +: bit! ( b pos v -- v ) >r 1 swap 7 swap - lshift dup invert r> and >r swap 0<> and r> or ; +: cram! ( b x y -- ) cr& 8 /mod cram + dup >r c@ bit! r> c! ; +: cram@ ( x y -- b ) cr& 8 /mod cram + c@ swap 7 swap - rshift 1 and 0<> ; ( UNTESTED ) + +forth definitions + diff --git a/pico-ice/ice40/ice40_layout.fs b/pico-ice/ice40/ice40_layout.fs new file mode 100644 index 0000000..feb42ad --- /dev/null +++ b/pico-ice/ice40/ice40_layout.fs @@ -0,0 +1,795 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +needs ice40_config.fs +needs flyclasses.fs + +ice40 definitions +vocabulary synthesis synthesis definitions +also flyclasses + +54 constant logic-width +42 constant ram-width +logic-width ram-width - constant logicram-diff + +flyclass CramBit +flyclass CramCell + flyclass Output + flyclass Input + flyclass Input0 + flyclass Input1 + flyclass Input2 + flyclass Input3 + flyclass LocalG + flyclass LocalG0 + flyclass LocalG1 + flyclass LocalG2 + flyclass LocalG3 + flyclass IOLocalG + flyclass IOLocalG0 + flyclass IOLocalG1 + flyclass SpanWire + flyclass Sp4HR + flyclass Sp4VB + flyclass Sp12HR + flyclass Sp12VB + flyclass IOPin + flyclass IOInput + flyclass IOOutput + flyclass IOOutput0 + flyclass IOOutput1 + flyclass IOEnable + flyclass IOFabOutput + flyclass LUTFFGlobal + flyclass FFSetReset + flyclass FFClock + flyclass FFEnable +flyclass GlobalNetwork +flyclass NotConnected + +method .create ( o -- o ) +method .optionCount ( o -- n ) +method .optionWire ( i o -- wire ) +method .getOption ( o -- n ) +method .setOption ( n o -- ) +method .print ( o -- ) + +method .getXY ( o -- x y ) +method .getBit ( o -- b ) ( overloaded for wires and CramBits ) +method .setBit ( b o -- ) +method .inside ( x y o -- o' ) +method .isLogic? ( o -- f ) +method .isRam? ( o -- f ) +method .isIO? ( o -- f ) +method .isBottom? ( o -- f ) +method .isInside? ( o -- f ) +method .listBits ( x o -- ) +method .enableBit ( o -- bit ) +method .inputEnableBit ( o -- bit ) +method .setNoResetBit ( o -- bit ) +method .asyncResetBit ( o -- bit ) +method .carryEnableBit ( o -- bit ) +method .dffEnableBit ( o -- bit ) +method .setPath ( n o -- ) +method .getPath ( o -- n ) +method .getInput ( n o -- wire ) +method .setLogic ( n o -- ) +method .getLogic ( o -- n ) +method .routes ( xt target o -- ) ( xt gets: bit wire ) +method .walk ( xt o -- ) ( xt gets: bit wire ) +method .makeOutput ( o -- ) +method .makeInput ( o -- ) +method .setPinType ( n o -- ) +method .getPinType ( o -- n ) +method .getParity ( o -- n ) +method .getRow ( o -- n ) + +initiate + +CramBit implementation + 0 cram-bank-width 2* 1- field x + 0 cram-height 1- field y + m: .create ( x y o -- o ) put y put x ;m + m: .print { o -- } ." CramBit(" o x . ." , " o y . ." ) " ;m + m: .setBit { b o -- } b o x o y cram! ;m + m: .getBit { o -- b } o x o y cram@ ;m + +: Sp4RVB { x y i -- o } x 1+ y i Sp4VB .create ; + +: span4_horz { i o -- wire } o .getXY i Sp4HR .create ; +: span4_vert { i o -- wire } + o .isBottom? if + o .getXY 1+ i Sp4VB .create + else + i 35 > if NotConnected .create exit then + o .getXY i Sp4VB .create + then ; +: span12_vert { i o -- wire } + o .isBottom? if + o .getXY 1+ i Sp12VB .create + else + i 21 > if NotConnected .create exit then + o .getXY i Sp12VB .create + then ; + +CramCell implementation + -13 cells-width 13 + 1- field cx + -13 cells-height 13 + 1- field cy + m: .create ( x y o -- o ) put cy put cx ;m + m: .print { o -- } ." CramCell(" o cx . ." , " o cy . ." ) " ;m + m: .getXY { o -- cx cy } o cx o cy ;m + m: .inside { x y o -- o' } o cx 54 * x + + o cx 6 > if logicram-diff - then + o cx 19 > if logicram-diff - then + o cy 16 * y + CramBit .create ;m + m: .isInside? { o -- f } o cx 0 >= o cx cells-width < and + o cy 0 >= o cy cells-height < and and ;m + m: .isIO? { o -- f } o cx 0 = o cx cells-width 1- = or + o cy 0 = or o cy cells-height 1- = or ;m + m: .isBottom? { o -- g } o cy 0= ;m + m: .isRam? { o -- f } o cx bram-column1 = o cx bram-column2 = or o .isIO? 0= and ;m + m: .isLogic? { o -- f } o .isRam? 0= o .isIO? 0= and ;m + : route12 { x y i m n target xt o } + target i o span12_vert = if + x y o .inside o .getXY m n IOInput .create xt execute + then ; + : route4v { x y i m n target xt o } + target i o span4_vert = if + x y o .inside o .getXY m n IOInput .create xt execute + then ; + : route4h { x y i m n target xt o } + target i o span4_horz = if + x y o .inside o .getXY m n IOInput .create xt execute + then ; + m: .routes { xt target o -- } + o .isIO? if + 5 1 0 0 0 target xt o route12 + 5 3 8 0 0 target xt o route12 + 5 5 16 0 0 target xt o route12 + 23 0 16 0 0 target xt o route4v + 23 1 0 0 0 target xt o route4v + 23 2 40 0 0 target xt o route4v + 23 3 4 0 0 target xt o route4h + 25 0 24 0 0 target xt o route4v + 25 1 8 0 0 target xt o route4v + 25 2 0 0 0 target xt o route4h + 25 3 8 0 0 target xt o route4h + 26 1 32 0 0 target xt o route4v + 26 2 12 0 0 target xt o route4h + + 4 6 2 0 1 target xt o route12 + 5 6 10 0 1 target xt o route12 + 4 7 18 0 1 target xt o route12 + 23 4 18 0 1 target xt o route4v + 23 5 2 0 1 target xt o route4v + 23 6 42 0 1 target xt o route4v + 23 7 5 0 1 target xt o route4h + 25 4 26 0 1 target xt o route4v + 25 5 10 0 1 target xt o route4v + 25 6 1 0 1 target xt o route4h + 25 7 9 0 1 target xt o route4h + 26 5 34 0 1 target xt o route4v + 26 6 13 0 1 target xt o route4h + + 4 9 4 1 0 target xt o route12 + 5 9 12 1 0 target xt o route12 + 4 8 20 1 0 target xt o route12 + 23 8 20 1 0 target xt o route4v + 23 9 4 1 0 target xt o route4v + 23 10 44 1 0 target xt o route4v + 23 11 6 1 0 target xt o route4h + 25 8 28 1 0 target xt o route4v + 25 9 12 1 0 target xt o route4v + 25 10 2 1 0 target xt o route4h + 25 11 10 1 0 target xt o route4h + 26 9 36 1 0 target xt o route4v + 26 10 14 1 0 target xt o route4h + + 5 10 6 1 1 target xt o route12 + 5 12 14 1 1 target xt o route12 + 5 14 22 1 1 target xt o route12 + 23 12 22 1 1 target xt o route4v + 23 13 6 1 1 target xt o route4v + 23 14 46 1 1 target xt o route4v + 23 15 7 1 1 target xt o route4h + 25 12 30 1 1 target xt o route4v + 25 13 14 1 1 target xt o route4v + 25 14 3 1 1 target xt o route4h + 25 15 11 1 1 target xt o route4h + 26 13 38 1 1 target xt o route4v + 26 13 15 1 1 target xt o route4h + exit + then + o .isInside? 0= if exit then + 8 0 do + target o .getXY i 2* Sp4HR .create = if + 46 i 2* 1+ o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 16 + Sp4HR .create = if + 46 i 2* o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 32 + Sp4HR .create = if + 47 i 2* 1+ o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 1+ Sp4RVB = if + 52 i 2* 1+ o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 17 + Sp4RVB = if + 53 i 2* o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 33 + Sp4RVB = if + 53 i 2* 1+ o .inside o .getXY i Output .create xt execute + then + loop + 4 0 do + target o .getXY i 2* 8 + Sp12HR .create = if + 47 i 2* o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* Sp12HR .create = if + 47 i 2* 8 + o .inside o .getXY i 4 + Output .create xt execute + then + + target o .getXY i 2* Sp4VB .create = if + 48 i 2* o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 16 + Sp4VB .create = if + 48 i 2* 1+ o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 16 + Sp12HR .create = if + 48 i 2* 8 + o .inside o .getXY i 4 + Output .create xt execute + then + target o .getXY i 2* 8 + Sp4VB .create = if + 48 i 2* 1+ 8 + o .inside o .getXY i 4 + Output .create xt execute + then + + target o .getXY i 2* Sp12VB .create = if + 51 i 2* o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 32 + Sp4VB .create = if + 51 i 2* 1+ o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 40 + Sp4VB .create = if + 51 i 2* 8 + o .inside o .getXY i 4 + Output .create xt execute + then + target o .getXY i 2* 24 + Sp4VB .create = if + 51 i 2* 1+ 8 + o .inside o .getXY i 4 + Output .create xt execute + then + + target o .getXY i 2* 16 + Sp12VB .create = if + 52 i 2* o .inside o .getXY i Output .create xt execute + then + target o .getXY i 2* 8 + Sp4VB .create = if + 52 i 2* 8 + o .inside o .getXY i 4 + Output .create xt execute + then + loop + ;m + +: getBits { n i w -- n i } n w .getBit 1 and i lshift or i 1+ ; +: setBits { n w -- n } n 1 and w .setBit n 2/ ; + +Output implementation CramCell extension + 0 7 field bit + m: .create { cx cy b o -- o } cx cy o CramCell :: .create b swap put bit ;m + m: .print { o -- } ." Output(" o .getXY swap . . ." , " o bit . ." ) " ;m + m: .getBit ( o -- b ) bit ;m + m: .optionCount { o -- n } 0 ;m + m: .optionWire ( i o -- wire ) abort ;m + m: .setOption ( n o -- ) abort ;m + m: .getOption { o -- n } 0 ;m + create input_table Input0 , Input1 , Input2 , Input3 , + m: .getInput { n o -- wire } o .getXY o .getBit n cells input_table + @ .create ;m + create logic_table $04 c, $14 c, $15 c, $05 c, $06 c, $16 c, $17 c, $07 c, + $03 c, $13 c, $12 c, $02 c, $01 c, $11 c, $10 c, $00 c, + m: .setLogic { n o -- } n ['] setBits o .listBits drop ;m + m: .getLogic { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .listBits { x o -- } 16 0 do + i logic_table + c@ 16 /mod >r 36 + r> o .getBit 2* + o .inside x execute + loop ;m + m: .setNoResetBit { o -- bit } 44 o .getBit 2* 1+ o .inside ;m + m: .asyncResetBit { o -- bit } 45 o .getBit 2* 1+ o .inside ;m + m: .carryEnableBit { o -- bit } 44 o .getBit 2* o .inside ;m + m: .dffEnableBit { o -- bit } 45 o .getBit 2* o .inside ;m + +Input implementation Output extension + m: .getPath { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .setPath { n o -- } n ['] setBits o .listBits drop ;m + m: .optionCount { o -- n } 17 ;m + m: .getOption { o -- n } o .enableBit .getBit if + o .getPath 1+ + else + 0 + then ;m + m: .setOption { n o -- } n if + -1 o .enableBit .setBit + n 1- o .setPath + else + 0 o .enableBit .setBit + 0 o .setPath ( for good measure ) + then ;m + +: inOptWire { i o lo hi -- wire } + i 0= if NotConnected .create exit then + i 1- 2 rshift 3 and { rt } + o .getXY + o .getBit 1 and if hi else lo then rt rshift 1 and i 1- 2* or + LocalG .create +; + +Input0 implementation Input extension + m: .print { o -- } ." Input0(" o .getXY swap . . ." , " o .getBit . ." ) " ;m + m: .enableBit { o -- wire } 29 o .getBit 2* 1+ o .inside ;m + m: .listBits { x o -- } 26 o .getBit 2* 1+ o .inside x execute + 26 o .getBit 2* o .inside x execute + 27 o .getBit 2* 1+ o .inside x execute + 28 o .getBit 2* 1+ o .inside x execute ;m + m: .optionWire ( i o -- wire ) $a $5 inOptWire ;m + +Input1 implementation Input extension + m: .print { o -- } ." Input1(" o .getXY swap . . ." , " o .getBit . ." ) " ;m + m: .enableBit { o -- wire } 29 o .getBit 2* o .inside ;m + m: .listBits { x o -- } 30 o .getBit 2* 1+ o .inside x execute + 30 o .getBit 2* o .inside x execute + 27 o .getBit 2* o .inside x execute + 28 o .getBit 2* o .inside x execute ;m + m: .optionWire ( i o -- wire ) $5 $a inOptWire ;m + +Input2 implementation Input extension + m: .print { o -- } ." Input2(" o .getXY swap . . ." , " o .getBit . ." ) " ;m + m: .enableBit { o -- wire } 32 o .getBit 2* 1+ o .inside ;m + m: .listBits { x o -- } 35 o .getBit 2* 1+ o .inside x execute + 35 o .getBit 2* o .inside x execute + 34 o .getBit 2* 1+ o .inside x execute + 33 o .getBit 2* 1+ o .inside x execute ;m + m: .optionWire ( i o -- wire ) $a $5 inOptWire ;m + +Input3 implementation Input extension + m: .print { o -- } ." Input3(" o .getXY swap . . ." , " o .getBit . ." ) " ;m + m: .enableBit { o -- wire } 32 o .getBit 2* o .inside ;m + m: .listBits { x o -- } 31 o .getBit 2* 1+ o .inside x execute + 31 o .getBit 2* o .inside x execute + 34 o .getBit 2* o .inside x execute + 33 o .getBit 2* o .inside x execute ;m + m: .optionWire ( i o -- wire ) $5 $a inOptWire ;m + +LocalG implementation CramCell extension + 0 31 field identifier + create localg_table LocalG0 , LocalG1 , LocalG2 , LocalG3 , + m: .create { cx cy id o -- o } + id 4 mod cells localg_table + @ to o + cx cy o CramCell :: .create id swap put identifier ;m + m: .print { o -- } ." LocalG(" o .getXY swap . . ." , g" o identifier 8 /mod . . ." ) " ;m + m: .getPath { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .setPath { n o -- } n ['] setBits o .listBits drop ;m + m: .optionCount { o -- n } 15 ;m + m: .getBit { o -- n } o identifier 4 / 8 mod ;m + m: .getOption { o -- n } o .enableBit .getBit if + o .getPath 1- + else + 0 + then ;m + m: .setOption { n o -- } n if + -1 o .enableBit .setBit + n 1+ o .setPath + else + 0 o .enableBit .setBit + 0 o .setPath ( for good measure ) + then ;m + : sp4skew { id off -- n } id 8 mod id 16 >= if 24 + then off + ; + : sp12skew { id off -- n cls } id 8 mod off + id 16 >= if Sp12VB else Sp12HR then ; + m: .optionWire { i o -- wire } + i 0 >= assert i o .optionCount < assert + i 0= if NotConnected .create exit then + i case + ( TODO: shift by 2 and add r_v_b ) + 6 of o .getXY o identifier 0 sp12skew .create exit endof + 7 of o .getXY o identifier 8 sp12skew .create exit endof + 8 of o .getXY o identifier 16 sp12skew .create exit endof + 9 of o .getXY o identifier 16 sp4skew Sp4VB .create exit endof + 10 of o .getXY o identifier 0 sp4skew Sp4HR .create exit endof + 11 of o .getXY o identifier 0 sp4skew Sp4VB .create exit endof + 12 of o .getXY o identifier 8 sp4skew Sp4VB .create exit endof + 13 of o .getXY o identifier 8 sp4skew Sp4HR .create exit endof + 14 of o .getXY o identifier 16 sp4skew Sp4HR .create exit endof + endcase + o identifier 16 < if + i case + 1 of 0 -1 endof + 2 of 0 1 endof + 3 of 0 0 endof + 4 of 1 -1 endof + 5 of -1 0 endof + endcase + else + i case + 1 of 1 1 endof + 2 of -1 1 endof + 3 of 0 0 endof + 4 of -1 -1 endof + 5 of 1 0 endof + endcase + then + { x y } + o .getXY y + to y x + to x + x 1 < if NotConnected .create exit then + x cells-width 1- >= if NotConnected .create exit then + y cells-height >= if NotConnected .create exit then + y 0< if NotConnected .create exit then + x y o identifier 8 mod Output .create + ;m + +LocalG0 implementation LocalG extension + m: .enableBit { o -- wire } 17 o .getBit 2* 1+ o .inside ;m + m: .listBits { x o -- } 14 o .getBit 2* 1+ o .inside x execute + 15 o .getBit 2* 1+ o .inside x execute + 14 o .getBit 2* o .inside x execute + 16 o .getBit 2* 1+ o .inside x execute ;m + +LocalG1 implementation LocalG extension + m: .enableBit { o -- wire } 17 o .getBit 2* o .inside ;m + m: .listBits { x o -- } 18 o .getBit 2* 1+ o .inside x execute + 15 o .getBit 2* o .inside x execute + 18 o .getBit 2* o .inside x execute + 16 o .getBit 2* o .inside x execute ;m + +LocalG2 implementation LocalG extension + m: .enableBit { o -- wire } 22 o .getBit 2* 1+ o .inside ;m + m: .listBits { x o -- } 25 o .getBit 2* 1+ o .inside x execute + 24 o .getBit 2* 1+ o .inside x execute + 25 o .getBit 2* o .inside x execute + 23 o .getBit 2* 1+ o .inside x execute ;m + +LocalG3 implementation LocalG extension + m: .enableBit { o -- wire } 22 o .getBit 2* o .inside ;m + m: .listBits { x o -- } 21 o .getBit 2* 1+ o .inside x execute + 24 o .getBit 2* o .inside x execute + 21 o .getBit 2* o .inside x execute + 23 o .getBit 2* o .inside x execute ;m + +create iopermy 0 , 1 , 3 , 2 , 4 , 5 , 7 , 6 , 8 , 9 , 11 , 10 , 12 , 13 , 15 , 14 , +: >iopermy ( n -- n ) cells iopermy + @ ; + +IOLocalG implementation CramCell extension + 0 15 field identifier + create localg_table IOLocalG0 , IOLocalG1 , + m: .create { cx cy id o -- o } + id 2 mod cells localg_table + @ to o + cx cy o CramCell :: .create id swap put identifier ;m + m: .print { o -- } ." IOLocalG(" o .getXY swap . . ." , g" o identifier 8 /mod . . ." ) " ;m + m: .inside { x y o -- wire } x y >iopermy o .isBottom? if 15 swap - then o CramCell :: .inside ;m + m: .getPath { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .setPath { n o -- } n ['] setBits o .listBits drop ;m + m: .optionCount { o -- n } 15 ;m + m: .getBit { o -- n } o identifier 8 mod ;m + m: .getRow { o -- n } o identifier 2/ ;m + m: .getOption { o -- n } o .enableBit .getBit if + o .getPath 1- + else + 0 + then ;m + m: .setOption { n o -- } n if + -1 o .enableBit .setBit + n 1+ o .setPath + else + 0 o .enableBit .setBit + 0 o .setPath ( for good measure ) + then ;m + : iosp4v { offset o -- wire } o .getBit offset + o span4_vert ; + : iosp12v { offset o -- wire } o .getBit offset + o span12_vert ; + : iosp4h { offset o -- wire } o .getBit offset + o span4_horz ; + m: .optionWire { i o -- wire } + i 0 >= assert i o .optionCount < assert + i 0= if NotConnected .create exit then + 1 +to i ( There's no 1 ) + i case + 5 of 0 o iosp4h exit endof + 6 of 8 o iosp4h exit endof + 7 of 0 o iosp12v exit endof + 8 of 8 o iosp12v exit endof + 9 of 16 o iosp12v exit endof + 10 of 0 o iosp4v exit endof + 11 of 8 o iosp4v exit endof + 12 of 16 o iosp4v exit endof + 13 of 24 o iosp4v exit endof + 14 of 32 o iosp4v exit endof + 15 of 40 o iosp4v exit endof + endcase + i 3 - 1 o .getXY nip if negate then { x y } + o .getXY y + to y x + to x + ( Could use .isLogic ? ) + x 1 < if NotConnected .create exit then + x cells-width 1- >= if NotConnected .create exit then + y cells-height 1- >= if NotConnected .create exit then + y 1 < if NotConnected .create exit then + x y o .getBit Output .create + ;m + +IOLocalG0 implementation IOLocalG extension + m: .enableBit { o -- wire } 19 o .getRow 2* 1+ o .inside ;m + m: .listBits { x o -- } 16 o .getRow 2* 1+ o .inside x execute + 16 o .getRow 2* o .inside x execute + 17 o .getRow 2* 1+ o .inside x execute + 18 o .getRow 2* 1+ o .inside x execute ;m + +IOLocalG1 implementation IOLocalG extension + m: .enableBit { o -- wire } 19 o .getRow 2* o .inside ;m + m: .listBits { x o -- } 20 o .getRow 2* 1+ o .inside x execute + 20 o .getRow 2* o .inside x execute + 17 o .getRow 2* o .inside x execute + 18 o .getRow 2* o .inside x execute ;m + +: optcount { n bit wire -- n } n 1+ ; +: optget { goal n bit wire -- goal n } bit .getBit if n else goal then n 1+ ; +: optset { goal n bit wire -- goal n } goal n = bit .setBit goal n 1+ ; +: optwire { answer goal n bit wire -- answer goal n } n goal = if wire else answer then goal n 1+ ; +: cross { idx n -- off ii } idx n /mod swap over 1 and xor ; + +SpanWire implementation CramCell extension + m: .optionCount { o -- n } 1 ['] optcount o .walk ;m + m: .getOption { o -- n } 0 1 ['] optget o .walk drop ;m + m: .setOption { n o -- } n 1 ['] optset o .walk 2drop ;m + m: .optionWire { i o -- wire } NotConnected .create i 1 ['] optwire o .walk 2drop ;m + +Sp4HR implementation SpanWire extension + 0 11 field index + m: .create { cx cy idx o -- o } cx idx 12 cross { ii } - cy o SpanWire :: .create + ii swap put index ;m + m: .print { o -- } ." Sp4HR(" o .getXY swap . . ." , " o index . ." ) " ;m + m: .walk { xt o -- } 6 -5 do xt o o .getXY swap i + swap CramCell .create .routes loop ;m + +Sp4VB implementation SpanWire extension + 0 11 field index + m: .create { cx cy idx o -- o } cx cy idx 12 cross { ii } + o SpanWire :: .create + ii swap put index ;m + m: .print { o -- } ." Sp4VB(" o .getXY swap . . ." , " o index . ." ) " ;m + m: .walk { xt o -- } 6 -5 do xt o o .getXY i + CramCell .create .routes loop ;m + +Sp12HR implementation SpanWire extension + 0 1 field index + m: .create { cx cy idx o -- o } cx idx 2 cross { ii } - cy o SpanWire :: .create + ii swap put index ;m + m: .print { o -- } ." Sp12HR(" o .getXY swap . . ." , " o index . ." ) " ;m + m: .walk { xt o -- } 13 -13 do xt o o .getXY swap i + swap CramCell .create .routes loop ;m + +Sp12VB implementation SpanWire extension + 0 1 field index + m: .create { cx cy idx o -- o } cx cy idx 2 cross { ii } + o SpanWire :: .create + ii swap put index ;m + m: .print { o -- } ." Sp12VB(" o .getXY swap . . ." , " o index . ." ) " ;m + m: .walk { xt o -- } 13 -13 do xt o o .getXY i + CramCell .create .routes loop ;m + +IOPin implementation CramCell extension + 0 1 field pinIndex + m: .create { x y pin o -- o } x y o CramCell :: .create pin swap put pinIndex ;m + m: .print { o -- } ." IOPin(" o .getXY swap . . o pinIndex . ." ) " ;m + m: .inside { x y o -- wire } o .getXY nip 0= if 15 y - to y then x y o CramCell :: .inside ;m + : nopullup { o -- } + o pinIndex 0= if + -1 37 7 o .inside .setBit + else + -1 37 12 o .inside .setBit + then + ; + m: .makeInput { o -- } + 1 o .setPinType + -1 o .enableBit .setBit + -1 o .inputEnableBit .setBit + o nopullup +( + o .getXY o pinIndex 0 IOInput .create +) + o .getXY o pinIndex 2* Output .create + ;m + m: .makeOutput { o -- output } + 25 o .setPinType + -1 o .enableBit .setBit + 0 o .inputEnableBit .setBit + o nopullup + o .getXY o pinIndex IOOutput0 .create + ;m + m: .getPinType { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .setPinType { n o -- } n ['] setBits o .listBits drop ;m + m: .listBits { x o -- ... } + 5 2 o pinIndex 11 * + o .inside x execute + 4 2 o pinIndex 11 * + o .inside x execute + 5 0 o pinIndex 11 * + o .inside x execute + 4 0 o pinIndex 11 * + o .inside x execute + 4 4 o pinIndex 11 * + o .inside x execute + 5 4 o pinIndex 11 * + o .inside x execute + ;m + m: .enableBit { o -- bit } o pinIndex if 27 1 else 26 7 then o .inside ;m + m: .inputEnableBit { o -- bit } 27 9 o pinIndex 1 xor 2* - o .inside ;m + +: ioOptWire { i o parity -- wire } + o .getXY i 2* parity xor i 4 >= if 1 xor then IOLocalG .create +; + +IOInput implementation SpanWire extension + 0 1 field pinIndex + 0 1 field dinNum + m: .create { x y pin din o -- o } x y o CramCell :: .create pin swap put pinIndex din swap put dinNum ;m + m: .print { o -- } ." IOInput(" o .getXY swap . . o pinIndex . o dinNum . ." ) " ;m + m: .optionCount { o -- n } 0 ;m + m: .getOption { o -- n } 0 ;m + +IOOutput implementation CramCell extension + 0 1 field pinIndex + m: .create { x y pin o -- o } x y o CramCell :: .create pin swap put pinIndex ;m + m: .print { o -- } ." IOOutput(" o .getXY swap . . o pinIndex . ." ) " ;m + m: .inside { x y o -- wire } x y o .isBottom? if 15 swap - then o CramCell :: .inside ;m + m: .getPath { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .setPath { n o -- } n ['] setBits o .listBits drop ;m + m: .optionCount { o -- n } 9 ;m + m: .getOption { o -- n } o .enableBit .getBit if + o .getPath 1+ + else + 0 + then ;m + m: .setOption { n o -- } n if + -1 o .enableBit .setBit + n 1- o .setPath + else + 0 o .enableBit .setBit + 0 o .setPath ( for good measure ) + then ;m + m: .optionWire { i o -- wire } + i 0= if NotConnected .create exit then + i 1- o o pinIndex o .getParity xor ioOptWire ;m + +IOOutput0 implementation IOOutput extension + m: .print { o -- } ." IOOutput0(" o .getXY swap . . o pinIndex . ." ) " ;m + m: .enableBit { o -- wire } 35 5 o pinIndex 5 * + o .inside ;m + m: .listBits { x o -- ... } + 34 5 o pinIndex 5 * + o .inside x execute + 35 4 o pinIndex 7 * + o .inside x execute + 34 4 o pinIndex 7 * + o .inside x execute + ;m + m: .getParity { o -- n } 0 ;m + +IOOutput1 implementation IOOutput extension + m: .print { o -- } ." IOOutput1(" o .getXY swap . . o pinIndex . ." ) " ;m + m: .enableBit { o -- wire } 33 9 o .inside ;m + m: .listBits { x o -- ... } + 32 9 o pinIndex 5 * + o .inside x execute + 32 8 o pinIndex 7 * + o .inside x execute + 33 8 o pinIndex 7 * + o .inside x execute + ;m + m: .getParity { o -- n } 1 ;m + +IOEnable implementation IOOutput extension + m: .print { o -- } ." IOEnable(" o .getXY swap . . o pinIndex . ." ) " ;m + m: .enableBit { o -- wire } 33 5 o .inside ;m + m: .listBits { x o -- ... } + 32 5 o pinIndex 5 * + o .inside x execute + 32 4 o pinIndex 7 * + o .inside x execute + 33 4 o pinIndex 7 * + o .inside x execute + ;m + m: .getParity { o -- n } 1 ;m + +IOFabOutput implementation IOOutput extension + m: .create { x y o -- o } x y 0 o IOOutput :: .create ;m + m: .print { o -- } ." IOFabOutput(" o .getXY swap . . ." ) " ;m + m: .enableBit { o -- wire } 37 4 o .inside ;m + m: .listBits { x o -- ... } + 37 5 o .inside x execute + 36 4 o .inside x execute + 36 5 o .inside x execute + ;m + m: .getParity { o -- n } 0 ;m + +LUTFFGlobal implementation CramCell extension + m: .print { o -- } ." LUTFFGlobal(" o .getXY swap . . ." ) " ;m + m: .getPath { o -- n } 0 0 ['] getBits o .listBits drop ;m + m: .setPath { n o -- } n ['] setBits o .listBits drop ;m + m: .optionCount { o -- n } 9 ;m + m: .getOption { o -- n } o .enableBit .getBit if + o .getPath 1+ + else + 0 + then ;m + m: .setOption { n o -- } n if + -1 o .enableBit .setBit + n 1- o .setPath + else + 0 o .enableBit .setBit + 0 o .setPath ( for good measure ) + then ;m + m: .optionWire { i o -- wire } + o .getXY i case + ( TODO: glb_netwk ) + 5 of 0 o .getRow + LocalG .create exit endof + 6 of 9 o .getRow + LocalG .create exit endof + 7 of 16 o .getRow + LocalG .create exit endof + 8 of 25 o .getRow + LocalG .create exit endof + endcase 2drop NotConnected .create ;m + +FFSetReset implementation LUTFFGlobal extension + m: .print { o -- } ." FFSetReset(" o .getXY swap . . ." ) " ;m + m: .enableBit { o -- wire } 1 14 o .inside ;m + m: .listBits { x o -- ... } + 0 15 o .inside x execute + 0 14 o .inside x execute + 1 15 o .inside x execute + ;m + m: .getRow ( -- n ) 4 ;m + m: .optionWire { i o -- wire } + i 0 > i 5 < and if i 1- 2* GlobalNetwork .create exit then + i o LUTFFGlobal :: .optionWire ;m + +FFEnable implementation LUTFFGlobal extension + m: .print { o -- } ." FFEnable(" o .getXY swap . . ." ) " ;m + m: .enableBit { o -- wire } 1 4 o .inside ;m + m: .listBits { x o -- ... } + 0 5 o .inside x execute + 0 4 o .inside x execute + 1 5 o .inside x execute + ;m + m: .getRow ( -- n ) 2 ;m + m: .optionWire { i o -- wire } + i 0 > i 5 < and if i 1- 2* 1+ GlobalNetwork .create exit then + i o LUTFFGlobal :: .optionWire ;m + +FFClock implementation LUTFFGlobal extension + m: .print { o -- } ." FFClock(" o .getXY swap . . ." ) " ;m + m: .enableBit { o -- wire } 2 2 o .inside ;m + m: .optionCount { o -- n } 13 ;m + m: .listBits { x o -- ... } + 0 3 o .inside x execute + 1 2 o .inside x execute + 0 2 o .inside x execute + 2 1 o .inside x execute + ;m + m: .optionWire { i o -- wire } + i 0 > i 9 < and if i 1- GlobalNetwork .create exit then + i 4 - o LUTFFGlobal :: .optionWire ;m + +GlobalNetwork implementation + 0 7 field index + m: .create { i o -- o } i o put index ;m + m: .print { o -- } ." GlobalNetwork(" o index . ." ) " ;m + m: .getOption { o -- n } 0 ;m + m: .optionCount { o -- n } 0 ;m + +NotConnected implementation + m: .create ( o -- o ) ;m + m: .print { o -- } ." NotConnected" ;m + m: .getOption { o -- n } 0 ;m + m: .optionCount { o -- n } 0 ;m + +: pin ( n -- o ) pin#s IOPin .create ; + +: route { src dst -- f } + \ ." SRC: " src .print ." DST: " dst .print cr + src dst = if -1 exit then + dst .getOption { p } + p if src p dst .optionWire recurse exit then + dst .optionCount { n } + n 0 ?do + i dst .setOption + src i dst .optionWire recurse if -1 unloop exit then + 0 dst .setOption + loop 0 +; + +: route. { src dst } + ." ROUTE: " + begin src dst <> while + dst .print ." <- " + dst .getOption dst .optionWire to dst + repeat + src .print cr +; + +previous +forth definitions + diff --git a/pico-ice/ice40/ice40_storage.fs b/pico-ice/ice40/ice40_storage.fs new file mode 100644 index 0000000..a84e8ad --- /dev/null +++ b/pico-ice/ice40/ice40_storage.fs @@ -0,0 +1,203 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +needs ice40_config.fs + +ice40 definitions +vocabulary storage storage definitions + +: ew! ( n a -- ) over 8 rshift over c! 1+ c! ; +: w, ( n -- ) here ew! 2 allot ; + +create header1 + $ff c, $00 c, $00 c, $ff c, ( Init blop, maybe not needed? ) + $7e c, $aa c, $99 c, $7e c, ( Preamble ) + $51 c, $00 c, ( Frequency 0=low, 1=medium, 2=high ) + $01 c, $05 c, ( Reset CRC crc = 0xffff ) +here header1 - constant header1# + +create header2 + $92 c, $0020 w, ( Set flags bit0=nosleep bit5=warmboot ) + $62 c, cram-bank-width 1- w, ( Set bank width ) + $82 c, $0000 w, ( Set bank offset to 0 ) +here header2 - constant header2# + +0 value bank-id +0 value bank-height +create bank-header + $72 c, here to bank-height 0 w, ( Set bank height, 5k only, upper vs lower ) + $11 c, here to bank-id 0 c, ( Set bank ) + $01 c, $01 c, ( Prefix ) +here bank-header - constant bank-header# + +create bank-footer + $00 c, $00 c, ( Suffix ) +here bank-footer - constant bank-footer# + +create header3 + $72 c, bram-chunk-size w, ( Setting bank height? ) +here header3 - constant header3# + +0 value bram-bank +create bram-header1 + $11 c, here to bram-bank 0 c, ( Setting bank ) +here bram-header1 - constant bram-header1# + +0 value bram-offset +0 value bram-bank-width +create bram-header2 + $82 c, here to bram-offset 0 w, ( Setting bank offset ) + $62 c, here to bram-bank-width 0 w, ( Setting bank width ) +here bram-header2 - constant bram-header2# + +0 value footer-crc +create footer + $22 c, here to footer-crc $0000 w, ( CRC ) + $01 c, $06 c, ( Wakeup ) + $00 c, ( Padding ) +here footer - constant footer# + +variable crc16 +: +crc16 ( ch -- ) + 7 for + dup i rshift 1 and ( peel off one bit ) + crc16 uw@ 15 rshift xor if $1021 else 0 then + crc16 uw@ 2* xor crc16 w! + next + drop +; +: *crc16 ( a n -- ) for aft dup c@ +crc16 1+ then next drop ; +: crc-write ( a n output -- ) >r 2dup *crc16 r> execute ; + +: cram-write { output -- } + ( write header ) + header1 header1# output execute + $ffff crc16 w! + header2 header2# output crc-write + + ( Bank 0 ) + 0 bank-id c! + cram-height-lower bank-height ew! + bank-header bank-header# output crc-write + cram cram-bank-width cram-height-lower * 8 / output crc-write + bank-footer bank-footer# output crc-write + + ( Bank 1 ) + 1 bank-id c! + cram-height-upper bank-height ew! + bank-header bank-header# output crc-write + cram cram-bank-width cram-height-lower * 8 / + + cram-bank-width cram-height-upper * 8 / output crc-write + bank-footer bank-footer# output crc-write + + ( Bank 2 ) + 2 bank-id c! + cram-height-lower bank-height ew! + bank-header bank-header# output crc-write + cram cram-bank-width cram-height-lower cram-height-upper + * 8 / + + cram-bank-width cram-height-lower * 8 / output crc-write + bank-footer bank-footer# output crc-write + + ( Bank 3 ) + 3 bank-id c! + cram-height-upper bank-height ew! + bank-header bank-header# output crc-write + cram cram-bank-width cram-height-lower 2* cram-height-upper + * 8 / + + cram-bank-width cram-height-upper * 8 / output crc-write + bank-footer bank-footer# output crc-write + + ( BRAM Header ) + header3 header3# output crc-write + + ( BRAM Bank 0 ) + 0 bram-bank c! + bram-header1 bram-header1# output crc-write + + bram-chunk-size 0 * bram-offset ew! + bram-width-lower 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + bram-chunk-size 1 * bram-offset ew! + bram-width-lower 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + ( BRAM Bank 1 ) + 1 bram-bank c! + bram-header1 bram-header1# output crc-write + + bram-chunk-size 0 * bram-offset ew! + bram-width-upper 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + bram-chunk-size 1 * bram-offset ew! + bram-width-upper 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + ( BRAM Bank 2 ) + 2 bram-bank c! + bram-header1 bram-header1# output crc-write + + bram-chunk-size 0 * bram-offset ew! + bram-width-lower 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + bram-chunk-size 1 * bram-offset ew! + bram-width-lower 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + ( BRAM Bank 3 ) + 3 bram-bank c! + bram-header1 bram-header1# output crc-write + + bram-chunk-size 0 * bram-offset ew! + bram-width-upper 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + bram-chunk-size 1 * bram-offset ew! + bram-width-upper 1- bram-bank-width ew! + bram-header2 bram-header2# output crc-write + + ( write footer ) + $22 +crc16 ( Add first byte of footer ) + crc16 uw@ footer-crc ew! ( Update CRC ) + footer footer# output crc-write +; + +0 value save-fh +: save-write ( a n -- ) save-fh write-file throw ; + +ice40 definitions also storage + +: save ( a n -- ) + w/o bin create-file throw to save-fh + ['] save-write cram-write + save-fh close-file throw +; + +DEFINED? ice [IF] +also ice + DEFINED? ice_cram_open [IF] + +: deploy + ice_cram_open + ['] ice_cram_write cram-write + ice_cram_close +; + + [THEN] +previous +[THEN] + +previous +forth definitions diff --git a/pico-ice/ice40/ice40_synthesis.fs b/pico-ice/ice40/ice40_synthesis.fs new file mode 100644 index 0000000..5d81e7b --- /dev/null +++ b/pico-ice/ice40/ice40_synthesis.fs @@ -0,0 +1,104 @@ +\ Copyright 2025 Bradley D. Nelson +\ +\ Licensed under the Apache License, Version 2.0 (the "License"); +\ you may not use this file except in compliance with the License. +\ You may obtain a copy of the License at +\ +\ http://www.apache.org/licenses/LICENSE-2.0 +\ +\ Unless required by applicable law or agreed to in writing, software +\ distributed under the License is distributed on an "AS IS" BASIS, +\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +\ See the License for the specific language governing permissions and +\ limitations under the License. + +needs ice40_layout.fs +needs ice40_allocation.fs + +ice40 synthesis definitions + +39 constant LED_G +40 constant LED_B +41 constant LED_R + +: XOR1 ( a b -- o ) NotConnected NotConnected $6666 LUT4 ; +: OR1 ( a b -- o ) NotConnected NotConnected $eeee LUT4 ; +: AND1 ( a b -- o ) NotConnected NotConnected $8888 LUT4 ; +: INVERT1 ( a b -- o ) NotConnected NotConnected NotConnected $5555 LUT4 ; +: BUFFER1 ( a b -- o ) NotConnected NotConnected NotConnected $aaaa LUT4 ; + +: HA ( x y -- so co ) 2dup AND1 >r XOR1 r> ; +: FA ( x y z -- so co ) HA >r HA r> OR1 ; + +: BUS ( v bus -- bus ) here >r , , r> ; +: UNBUS ( bus -- v bus ) dup cell+ @ swap @ ; +: nBUS ( v* n -- bus ) 0 swap 0 ?do BUS loop ; +: nUNBUS ( bus -- v* ) begin dup while UNBUS repeat drop ; + +: NEARBY { wire -- wire } wire .getXY dup 2 < if 1+ else 1- then + 2dup CramCell .create .isRam? if >r 1+ r> then + PLACE wire ; + +: IN1PIN ( n -- bus ) pin .makeInput NEARBY BUFFER1 ; +: OUT1PIN! ( wire n -- ) pin .makeOutput NEARBY >r BUFFER1 r> route! ; + +: INPINS ( p1..pn n -- wire ) 0 swap 0 ?do swap IN1PIN swap BUS loop ; +: OUTPINS! ( bus p1..pn n -- ) + nBUS begin dup while + UNBUS >r swap UNBUS >r swap OUT1PIN! r> r> + repeat 2drop ; + +: REVERSE ( a -- a' ) + 0 swap begin dup while + UNBUS >r swap BUS r> + repeat drop +; + +: INVERT ( a -- a' ) + dup 0= if exit then + UNBUS >r INVERT1 r> recurse BUS +; + +: BUFFER ( a -- a' ) + dup 0= if exit then + UNBUS >r BUFFER1 r> recurse BUS +; + +: AND ( a b -- c ) + dup 0= if nip exit then + UNBUS >r >r UNBUS r> swap >r AND1 + r> r> recurse BUS +; + +: OR ( a b -- c ) + dup 0= if nip exit then + UNBUS >r >r UNBUS r> swap >r OR1 + r> r> recurse BUS +; + +: XOR ( a b -- c ) + dup 0= if nip exit then + UNBUS >r >r UNBUS r> swap >r XOR1 + r> r> recurse BUS +; + +: +c ( a b ci -- c ) + >r dup 0= if 2drop r> 0 BUS exit then r> + -rot + UNBUS >r >r UNBUS r> swap >r FA + r> r> rot recurse BUS +; + +: + ( a b -- c ) NotConnected +c ; + +: REGISTER ( n -- bus ) + 0 swap 0 ?do FFL swap BUS loop REVERSE ; + +: REG! ( v a -- ) + dup 0= if 2drop exit then + UNBUS >r >r UNBUS r> swap >r FF! + r> r> recurse +; + +forth definitions + diff --git a/pico-ice/main.c b/pico-ice/main.c index 203ebea..4f98c4f 100644 --- a/pico-ice/main.c +++ b/pico-ice/main.c @@ -29,9 +29,9 @@ #include "common/calls.h" #ifndef UEFORTH_SIM -# define HEAP_SIZE (100 * 1024) +# define HEAP_SIZE (150 * 1024) #else -# define HEAP_SIZE (200 * 1024) +# define HEAP_SIZE (300 * 1024) #endif #define STACK_CELLS (4 * 1024) diff --git a/pico-ice/pico_ice_boot.fs b/pico-ice/pico_ice_boot.fs index b2686b1..382fa64 100644 --- a/pico-ice/pico_ice_boot.fs +++ b/pico-ice/pico_ice_boot.fs @@ -18,5 +18,6 @@ needs ../common/phase2.fs needs ../common/tasks.fs needs ../common/streams.fs needs platform.fs +needs ice40/ice40.fs needs autoboot.fs needs ../common/fini.fs