aboutsummaryrefslogtreecommitdiff
path: root/scaf
diff options
context:
space:
mode:
Diffstat (limited to 'scaf')
-rw-r--r--scaf/COPYING340
-rw-r--r--scaf/Makefile22
-rw-r--r--scaf/Makefile.config34
-rw-r--r--scaf/README88
-rw-r--r--scaf/README.scaf98
-rw-r--r--scaf/include/Makefile6
-rw-r--r--scaf/include/pdp_ca.h71
-rw-r--r--scaf/modules/Makefile21
-rw-r--r--scaf/modules/carules.scaf117
-rw-r--r--scaf/pdp/Makefile13
-rw-r--r--scaf/pdp/pdp_ca.c725
-rw-r--r--scaf/pdp/pdp_ca_system.c228
-rw-r--r--scaf/system/Makefile21
-rw-r--r--scaf/system/kernel.scaf130
-rw-r--r--scaf/system/optim.rules74
-rw-r--r--scaf/system/scaf_feeder.s49
-rw-r--r--scaf/system/scaf_feeder_test.c30
-rwxr-xr-xscaf/system/scafc.pl269
-rw-r--r--scaf/system/scafmacro.s487
-rw-r--r--scaf/test/test_pdp_ca.pd132
-rw-r--r--scaf/test/test_pdp_ca2.pd154
21 files changed, 3109 insertions, 0 deletions
diff --git a/scaf/COPYING b/scaf/COPYING
new file mode 100644
index 0000000..7f87ef8
--- /dev/null
+++ b/scaf/COPYING
@@ -0,0 +1,340 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/scaf/Makefile b/scaf/Makefile
new file mode 100644
index 0000000..2ac26a5
--- /dev/null
+++ b/scaf/Makefile
@@ -0,0 +1,22 @@
+include Makefile.config
+
+all: pdp_scaf.pd_linux
+
+pdp_scaf_all:
+ make -C include
+ make -C system
+ make -C modules
+ make -C pdp
+
+clean:
+ rm -f *~
+ rm -f pdp_scaf.pd_linux
+ make -C include clean
+ make -C system clean
+ make -C modules clean
+ make -C pdp clean
+
+
+pdp_scaf.pd_linux: pdp_scaf_all
+ rm -f pdp_scaf.pd_linux
+ gcc -export_dynamic -shared -o pdp_scaf.pd_linux pdp/*.o system/scaf_feeder.o $(PDP_CA_LIBS)
diff --git a/scaf/Makefile.config b/scaf/Makefile.config
new file mode 100644
index 0000000..7106a9f
--- /dev/null
+++ b/scaf/Makefile.config
@@ -0,0 +1,34 @@
+# pd's directory
+PD_DIR = /home/tom/pd/distro/pd
+PDP_DIR = /home/tom/pd/packet
+
+#PD_DIR = /usr/local/pd
+#PDP_DIR = /usr/local/pdp
+
+SCAF_DIR = $(PDP_DIR)/scaf
+
+
+
+
+# build flags
+
+PDP_CA_INCLUDE = -I$(PD_DIR)/src -I$(PDP_DIR)/include -I$(SCAF_DIR)/include
+PDP_CA_LIBS = -ldl
+PDP_CA_AFLAGS =
+#--gstabs
+PDP_CA_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \
+ -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -g
+# -Wshadow
+
+# compiler and assembler
+CC = gcc-3.2
+#CC = gcc
+AS = as
+
+# build rules
+
+.c.o:
+ $(CC) $(PDP_CA_CFLAGS) $(PDP_CA_INCLUDE) -o $*.o -c $*.c
+.s.o:
+ $(AS) -o $*.o $*.s $(PDP_CA_AFLAGS)
diff --git a/scaf/README b/scaf/README
new file mode 100644
index 0000000..60ee4dd
--- /dev/null
+++ b/scaf/README
@@ -0,0 +1,88 @@
+PDP_SCAF for pdp v0.7
+Cellular Automata modules for PDP
+
+Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+The GNU Public Licence can be found in the file COPYING
+
+
+------------------------------------------------------------------
+
+This is a pdp extension lib that contains modules for cellular
+automata built on a (very) minimal forth-like virtual system
+(scaf - simple cellular automaton forth) to define update rules. a
+compiler is included to produce scafo object code that can be
+dynamically loaded into the pdp_ca module. so it is possible to
+add/change rules without restarting pd (note however you need to close
+all lib files before the dynamic loader reloads the lib). see
+scaf/README for details.
+
+
+pdp_ca2image and pdp_image2ca are included for conversion between
+CA packets and image packets. (pdp_ca2image produces greyscale
+images)
+
+Have a look at the patches in test/ for some crude docs. The file
+README.scaf contains some more info on the internals.
+
+
+Requirements:
+
+* pd
+* pdp
+* linux
+* perl for the forth compiler
+* an intel/amd processor that supports MMX
+
+
+Building:
+
+Edit Makefile.config to reflect your system settings. For now this
+should be the pd dir, the pdp dir and the pdp_scaf dir.
+
+type "make" in the top directory. Remember to type "make clean all"
+after editing Makefile.config
+
+
+Using:
+
+add "-lib <SCAF_DIR>/pdp_scaf" to the pd command line after the
+"-lib <PDP_DIR>/pdp" part.
+
+
+
+launch pd with the options -lib $PDP_DIR/pdp -path $PDP_DIR/abstractions
+
+Directory structure:
+
+include/ header files
+pdp/ pdp external code
+system/ forth system code
+test/ some test patches (cryptic doc)
+modules/ ca rule libraries
+
+
+
+Please let me know if you discover a bug or think something doesn't work
+right. Code, documentation or example patches are more than welcome of
+course.
+
+Have Fun,
+
+Tom
+
+last modified: 2003/01/12
diff --git a/scaf/README.scaf b/scaf/README.scaf
new file mode 100644
index 0000000..0035899
--- /dev/null
+++ b/scaf/README.scaf
@@ -0,0 +1,98 @@
+SCAF - simple cellular automaton forth
+
+scaf is a virtual machine / forth environment for binary arithmic
+tailored to 2D 1 cell neighbourhood cellular automata.
+
+scaf is a compiled language. programs run inside a "feeder"
+(sort of operating system if you want)
+
+the feeder is responsable for loading/storing CA cells
+from/to memory. data in memory is organized as a scanline
+encoded toroidial bitplane (lsb = left). to simplify the feeder
+and the stack machine, the top left corner of the rectangular grid
+of pixels will shift down every processing step. this enables
+to keep a cell neighbourhood in a couple of registers.
+
+the stack machine has the following architecture:
+CA stack: (%esi), TOS: %mm0 (32x2 cells. lsb = top left)
+CA horizon: (%edi) (64x4 cells. (%edi) = top row. lsb = left)
+
+scratch register: %mm1, %mm2
+bitmask register: %mm3 = 0xffffffffffffffff
+
+4 bit counter: %mm4-%mm7
+
+the stack size / organization is not known to the stack machine.
+it can be thought of as operating on a 3x3 cell neightbourhood.
+the only purpose of the forth program is to determine the CA local update rule.
+
+the machine is supposed to be very minimal. no looping control.
+no adressing modes. no conditional code. so recursion is not allowed
+(no way to stop it) there are 9 words to load the cell neigbourhood
+on the stack. the rest is just logic and stack manips.
+
+the counter can be used for counting neighbourhood cells, like in the
+game of life. the zero test and sign bit can be used for comparisons.
+there are kernel words for loading constants into the counter register,
+and for communication between stack and register.
+
+the horizon is limited to 3x3, however it can be easily extended to
+32x3. extending it further than that would require a redesign of the
+forth + feeder.
+
+
+HOW TO CREATE NEW CA RULES
+
+edit scaf/modules/carules.scaf or create your own source lib and add
+the name to the scaf/modules/Makefile. type make in scaf/modules
+to compile. if you get error messages from the assembler saying things
+like
+
+ Error: no such instruction: `xxx'
+
+ or
+ Error: invalid character '_' in mnemonic
+
+this means there are undefined words in your source file. since not
+all characters are allowed in an asm file, the offending characters are
+converted to _SOMETHINGELSE_
+
+if you are stuck somewhere, just look at the output of scaf.pl on
+your .scaf file to determine where the problem is.
+
+words that can be accessed from inside pdp_ca have to start with the
+prefix rule_ and have to leave a single item on the data stack (the return
+value) other rules can have all the stack effect you want, but for safety
+reasons they can't be accessed from within pdp_ca.
+
+
+
+FORTH SYSTEM CODE
+
+the forth system is made up of the following files:
+
+kernel.scaf: a collection of forth kernel words
+scafmacro.s: a set of asm macro definitions used in kernel.scaf
+optim.rules: some substitution rules to eliminate redundant
+ stack manipulations
+
+scaf.pl: the compiler
+
+scaf.pl is run like this:
+
+scaf.pl -Isystemdir source.scaf
+
+if the -I switch is left out, the current directory is searched
+for the system files. the compiler produces an assembler source
+that includes scafmacro.s on standard output.
+
+the code it produces is relatively fast. it only uses and/or/xor
+and shift mmx instructions. it's not optimal use of silicon but
+it's pretty fast given what's possible. the feeder routine could
+be improved though.
+
+porting to another platform would require a rewrite of scafmacro.s
+the rest can be reused. if the target machine has 64 bit registers
+(or if you can emulate this one using more registers) porting is
+relatively easy. for larger registers a small change needs to
+be made to the feeder routine in pdp_ca.c
diff --git a/scaf/include/Makefile b/scaf/include/Makefile
new file mode 100644
index 0000000..1aba02c
--- /dev/null
+++ b/scaf/include/Makefile
@@ -0,0 +1,6 @@
+current:
+
+
+clean:
+ rm -f *~
+
diff --git a/scaf/include/pdp_ca.h b/scaf/include/pdp_ca.h
new file mode 100644
index 0000000..acaeea7
--- /dev/null
+++ b/scaf/include/pdp_ca.h
@@ -0,0 +1,71 @@
+/*
+ * Cellular Automata Extension Module for pdp - Main header file
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PDP_CA_H
+#define PDP_CA_H
+
+#include "pdp.h"
+
+
+
+/* 2D CA DATA PACKET */
+typedef struct
+{
+ unsigned int encoding; /* CA data format */
+ unsigned int width; /* CA width (in 1 bit cells) */
+ unsigned int height; /* CA height (in 1 bit cells) */
+ unsigned int offset; /* bit offset of upper left corner */
+
+} t_ca;
+
+/* CA encodings */
+#define PDP_CA_STANDARD 1 /* rectangular CA */
+
+/* pdp data packet types */
+#define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */
+
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* some utility methods for CA */
+int pdp_type_isvalid_ca(int packet);
+int pdp_type_ca2grey(int packet);
+int pdp_type_grey2ca(int packet, short int threshold);
+
+/* returns a pointer to the ca subheader given the pdp header */
+t_ca *pdp_type_ca_info(t_pdp *x);
+
+/* mmx feeder routine */
+unsigned long long scaf_feeder(void *tos, void *reg, void (*ca_rule)(void), void *env);
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //PDP_CA_H
diff --git a/scaf/modules/Makefile b/scaf/modules/Makefile
new file mode 100644
index 0000000..7bb0dc9
--- /dev/null
+++ b/scaf/modules/Makefile
@@ -0,0 +1,21 @@
+OBJ = carules.scafo
+
+SCAFDIR = ../system
+
+.SUFFIXES: .scaf
+.SUFFIXES: .scafo
+
+.scaf.o:
+ $(SCAFDIR)/scafc.pl -I$(SCAFDIR) $*.scaf | as -o $*.o
+
+.o.scafo:
+ gcc -export_dynamic -shared -o $*.scafo $*.o
+ rm $*.o
+ strip --strip-unneeded $*.scafo
+
+all: $(OBJ)
+
+clean:
+ rm -f *.scafo
+ rm -f *~
+
diff --git a/scaf/modules/carules.scaf b/scaf/modules/carules.scaf
new file mode 100644
index 0000000..32aef4a
--- /dev/null
+++ b/scaf/modules/carules.scaf
@@ -0,0 +1,117 @@
+( Pure Data Packet - ca rules library. )
+( Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> )
+( )
+( This program is free software; you can redistribute it and/or modify )
+( it under the terms of the GNU General Public License as published by )
+( the Free Software Foundation; either version 2 of the License, or )
+( [at your option] any later version. )
+( )
+( This program is distributed in the hope that it will be useful, )
+( but WITHOUT ANY WARRANTY; without even the implied warranty of )
+( MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the )
+( GNU General Public License for more details. )
+( )
+( You should have received a copy of the GNU General Public License )
+( along with this program; if not, write to the Free Software )
+( Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. )
+
+
+
+( this is the standard ca rules library )
+( a rule that is accessible from the ouside should start with "rule_" )
+( and has to return exactly one item on the stack (this is checked in pdp_ca) )
+
+
+( a word is a sequence of non whitespace characters (\S+) )
+( words are separated by whitespace (\s+) )
+( so "word ;" is not the same as "word;" )
+
+( all words between the "(" word and the ")" word are ignored )
+
+( ":" starts a definition, the next word is the name of the new word )
+( newline ends a definition )
+
+( no more than one definition per line )
+( no more than one line per definition )
+
+( ";" returns to calling word )
+( if no ";" is encountered the next defined word is executed )
+( this is to have multiple entry points )
+( multiple exit points don't make sense since there are no conditional words )
+
+
+
+: +(4) ++++ ; ( 4 bit add TOS - carry on TOS )
+: +(3) +++ ; ( 3 bit add TOS - carry on TOS )
+: +(2) ++ ; ( 2 bit add TOS - carry on TOS )
+
+: +top @-+ +(4) drop @0+ +(4) drop @++ +(4) ; ( add top row to reg - carry on TOS )
+: +mid @-0 +(4) drop @00 +(4) drop @+0 +(4) ; ( add mid row to reg - carry on TOS )
+: +bot @-- +(4) drop @0- +(4) drop @+- +(4) ; ( add bot row to reg - carry on TOS )
+: +all +top drop +mid drop +bot ; ( add all cells to reg - carry on TOS )
+
+: +mid-1 @-0 +(4) drop @+0 +(4) ; ( add mid row except center element to reg - carry on TOS )
+: +all-1 +top drop +mid-1 drop +bot ; ( add all cells expet middle one to reg - carry on TOS )
+
+
+: countall a-0 +all drop ; ( count all cells - no stack effect )
+: countall-1 a-0 +all-1 drop ; ( count all cells except middle one - no stack effect )
+
+: +topbot @0+ +(3) drop @0- +(3) ;
+: +leftright @+0 +(3) drop @-0 +(3) ;
+: +star +topbot drop +leftright ;
+: countstar a-0 +star drop ;
+
+: =2or3? @a2 not @a1 and ; ( sum equal to 2 or 3? only checks 3 bits )
+: =3? =2or3? @a0 and ; ( sum equal to 3 ? )
+: =2? =2or3? @a0 not and ; ( sum equal to 2 ? )
+: =4? @a2 @a1 not and @a0 not and ; ( sum equal to 4 ? )
+
+
+
+( some test rules )
+
+( : rule_one 1 ; )
+( : rule_zero 0 ; )
+( : rule_id @00 ; )
+
+
+: rule_shiftleft @+0 ;
+: rule_shifttop @0- ;
+: rule_shiftbot @0+ ;
+: rule_shifttopright @-- ;
+: rule_strobe @00 not ;
+
+( game of life )
+
+: rule_gameoflife countall-1 =2? @00 and =3? or ;
+
+( wolfram's rule 110)
+
+: rule_w110 @00 @+0 and not @-0 @00 @+0 or or and ;
+
+
+( some other rules )
+
+: rule_w110mod @0+ @+0 and not @-+ @0+ @++ or or and ;
+
+: rule_w110mod2 @0+ @+0 and not @-+ @0+ @+0 or or and ;
+: rule_w110mod3 @0+ @++ and not @-+ @0+ @++ or or and @-0 @00 @+0 or or and ;
+
+: rule_golmod countall-1 =3? @00 and =2? or ;
+: rule_golmod2 countall-1 =2? @0+ and =3? or ;
+: rule_golmod3 countall-1 =2? @++ and =3? or ;
+: rule_golmod4 countall-1 =2? @++ @-- or and =3? or ;
+: rule_golmod5 countall-1 =2? @++ @-- or and =3? @+- and or ;
+: rule_golmod6 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or ;
+: rule_golmod7 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or @00 and ;
+
+( ca's with a short settling time )
+
+: rule_block countstar =4? not =2? and @00 or ;
+: rule_noiseedges countstar =4? =3? or not =2? and @00 or @++ xor ;
+: rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ;
+
+
+( : rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ; )
+
diff --git a/scaf/pdp/Makefile b/scaf/pdp/Makefile
new file mode 100644
index 0000000..73c8892
--- /dev/null
+++ b/scaf/pdp/Makefile
@@ -0,0 +1,13 @@
+current: all_modules
+
+include ../Makefile.config
+
+OBJECTS = pdp_ca.o pdp_ca_system.o
+
+
+all_modules: $(OBJECTS)
+
+clean:
+ rm -f *~
+ rm -f *.o
+
diff --git a/scaf/pdp/pdp_ca.c b/scaf/pdp/pdp_ca.c
new file mode 100644
index 0000000..391b235
--- /dev/null
+++ b/scaf/pdp/pdp_ca.c
@@ -0,0 +1,725 @@
+/*
+ * Pure Data Packet module for cellular automata
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp_ca.h"
+#include <dlfcn.h>
+#include <stdio.h>
+
+t_class *pdp_ca_class; // a cellular automaton processor: single input - single output
+//t_class *pdp_ca2_class; // double input - single output
+t_class *pdp_ca2image_class; // converter from ca -> grey/yv12
+t_class *pdp_image2ca_class; // converter from grey/yv12 -> ca
+
+
+// *********************** CA CLASS STUFF *********************
+
+
+
+#define PDP_CA_STACKSIZE 256
+
+typedef struct pdp_ca_data_struct
+{
+ unsigned int env[2*4];
+ unsigned int reg[2*4];
+ unsigned int stack[2*PDP_CA_STACKSIZE];
+ short int random_seed[4];
+} t_pdp_ca_data;
+
+typedef struct pdp_ca_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ int x_queue_id;
+
+ /* double buffering data packets */
+ int x_packet0;
+ int x_packet1;
+
+ /* some data on the ca_routine */
+ void (*x_ca_routine)(void);
+ void *x_ca_libhandle;
+ char *x_ca_rulenames;
+ int x_ca_nbrules;
+ char ** x_ca_rulename;
+
+ /* nb of iterations */
+ int x_iterations;
+
+
+
+ /* aligned vector data */
+ t_pdp_ca_data *x_data;
+
+ /* output packet type */
+ t_symbol *x_packet_type;
+
+} t_pdp_ca;
+
+
+
+/* process from packet0 -> packet1 */
+static void pdp_ca_process_ca(t_pdp_ca *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ unsigned int *data0 = (unsigned int *)pdp_packet_data (x->x_packet0);
+ unsigned int *data1 = (unsigned int *)pdp_packet_data (x->x_packet1);
+
+
+ int width = pdp_type_ca_info(header0)->width;
+ int height = pdp_type_ca_info(header0)->height;
+ int i,j;
+
+ /* load TOS in middle of buffer to limit the effect of stack errors */
+ unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)];
+ unsigned int *env = &x->x_data->env[0];
+ unsigned int *reg = &x->x_data->reg[0];
+ void *ca_routine = x->x_ca_routine;
+ unsigned int rtos;
+
+ int offset = pdp_type_ca_info(header0)->offset;
+ int xoffset = offset % width;
+ int yoffset = offset / width;
+
+ /* double word width: number of unsigned ints per row */
+ int dwwidth = width >> 5;
+
+ unsigned long long result = 0;
+
+ /* exit if there isn't a valid routine */
+ if(!ca_routine) return;
+
+ //post("pdp_ca: PRE offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
+
+ /* calculate new offset: lines shift up, rows shift left by 16 cells */
+ xoffset = (xoffset + width - 16) % width;
+ yoffset = (yoffset + height - 1) % height;
+
+ offset = yoffset * width + xoffset;
+
+ //post("pdp_ca: PST offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
+
+
+ pdp_type_ca_info(header1)->offset = offset;
+
+
+ for(j=0; j<dwwidth*(height - 2); j+=(dwwidth<<1)){
+ for(i=0; i < (dwwidth-1) ; i+=1){
+ env[0] = data0[i + j];
+ env[1] = data0[i + j + 1];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[i + j + dwwidth + 1];
+ env[4] = data0[i + j + (dwwidth<<1)];
+ env[5] = data0[i + j + (dwwidth<<1) + 1];
+ env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
+ env[7] = data0[i + j + (dwwidth<<1) + dwwidth + 1];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+ }
+ // i == dwwidth-1
+
+ env[0] = data0[i + j];
+ env[1] = data0[j];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[j + dwwidth];
+ env[4] = data0[i + j + (dwwidth<<1)];
+ env[5] = data0[j + (dwwidth<<1)];
+ env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
+ env[7] = data0[j + (dwwidth<<1) + dwwidth];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+ }
+
+ // j == dwwidth*(height - 2)
+ for(i=0; i < (dwwidth-1) ; i+=1){
+ env[0] = data0[i + j];
+ env[1] = data0[i + j + 1];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[i + j + dwwidth + 1];
+ env[4] = data0[i];
+ env[5] = data0[i + 1];
+ env[6] = data0[i + dwwidth];
+ env[7] = data0[i + dwwidth + 1];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+ }
+ // j == dwwidth*(height - 2)
+ // i == dwwidth-1
+ env[0] = data0[i + j];
+ env[1] = data0[j];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[j + dwwidth];
+ env[4] = data0[i];
+ env[5] = data0[0];
+ env[6] = data0[i + dwwidth];
+ env[7] = data0[dwwidth];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+
+
+
+ /* check data stack pointer */
+ rtos = (unsigned int)tos;
+
+ if (env[0] != rtos){
+ if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine");
+ if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item");
+ x->x_ca_routine = 0;
+ post("pdp_ca: rule disabled");
+
+ }
+
+ return;
+}
+
+
+static void pdp_ca_swappackets(t_pdp_ca *x)
+{
+ /* swap packets */
+ int packet = x->x_packet1;
+ x->x_packet1 = x->x_packet0;
+ x->x_packet0 = packet;
+}
+
+
+
+
+
+/* tick advance CA one timestep */
+static void pdp_ca_bang_thread(t_pdp_ca *x)
+{
+ int encoding;
+ int packet;
+ int i;
+
+ /* invariant: the two packets are allways valid and compatible
+ so a bang is allways possible. this means that in the pdp an
+ invalid packet needs to be converted to a valid one */
+
+ for(i=0; i < x->x_iterations; i++){
+
+ /* process form packet0 -> packet1 and propagate */
+ pdp_ca_process_ca(x);
+
+ /* swap */
+ pdp_ca_swappackets(x);
+
+ }
+
+}
+
+static void pdp_ca_sendpacket(t_pdp_ca *x)
+{
+ /* output the packet */
+ outlet_pdp(x->x_outlet0, x->x_packet0);
+}
+
+static void pdp_ca_bang(t_pdp_ca *x)
+{
+ /* we don't use input packets for testing dropping here
+ but check the queue_id to see if processing is
+ still going on */
+
+ if (-1 == x->x_queue_id){
+ pdp_queue_add(x, pdp_ca_bang_thread, pdp_ca_sendpacket, &x->x_queue_id);
+ }
+
+ else{
+ pdp_control_notify_drop(-1);
+ }
+}
+
+
+/* this method stores the packet into x->x_packet0 (the packet
+ to be processed) if it is valid. x->x_packet1 is not compatible
+ it is regenerated so that it is
+
+ in short, when this routine returns both packets are valid
+ and compatible.
+*/
+
+
+static void pdp_ca_copy_rw_if_valid(t_pdp_ca *x, int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+
+
+ int grabpacket;
+ int convertedpacket;
+
+ /* check if header is valid */
+ if (!header) return;
+
+ if (PDP_CA != header->type) return;
+ if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return;
+
+
+ /* packet is a ca, register it */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_rw(packet);
+
+
+ /* make sure we have the right header */
+ header = pdp_packet_header(x->x_packet0);
+
+
+ /* make sure that the other packet is compatible */
+ if ((pdp_type_ca_info(header1)->width != pdp_type_ca_info(header)->width) ||
+ (pdp_type_ca_info(header1)->height != pdp_type_ca_info(header)->height)) {
+
+ /* if not, throw away and clone the new one */
+ pdp_packet_mark_unused(x->x_packet1);
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ }
+
+
+};
+
+/* hot packet inlet */
+static void pdp_ca_input_0(t_pdp_ca *x, t_symbol *s, t_floatarg f)
+{
+
+ if (s == gensym("register_rw")){
+ pdp_ca_copy_rw_if_valid(x, (int)f);
+ }
+ else if (s == gensym("process")){
+ pdp_ca_bang(x);
+ }
+
+
+}
+
+/* cold packet inlet */
+static void pdp_ca_input_1(t_pdp_ca *x, t_symbol *s, t_floatarg f)
+{
+
+ if (s == gensym("register_rw"))
+ {
+ pdp_ca_copy_rw_if_valid(x, (int)f);
+ }
+
+}
+
+
+static void pdp_ca_rule_string(t_pdp_ca *x, char *c)
+{
+ char tmp[256];
+ void (*prev_routine)(void);
+
+ /* save previous routine ptr */
+ prev_routine = x->x_ca_routine;
+
+ /* check if we can find string */
+ sprintf(tmp, "rule_%s", c);
+ if (!(x->x_ca_routine = dlsym(x->x_ca_libhandle, tmp))){
+ post("pdp_ca: can't fine ca rule %s (symbol: %s)", c, tmp);
+ x->x_ca_routine = x->x_ca_routine;
+ return;
+ }
+
+ /* all seems ok */
+ //post("pdp_ca: using ca rule %s", c);
+
+}
+static void pdp_ca_rule(t_pdp_ca *x, t_symbol *s)
+{
+ /* make sure lib is loaded */
+ if (!x->x_ca_libhandle) return;
+
+ /* set rule by name */
+ pdp_ca_rule_string(x, s->s_name);
+}
+
+static void pdp_ca_rule_index(t_pdp_ca *x, t_float f)
+{
+ int i = (int)f;
+
+ /* make sure lib is loaded */
+ if (!x->x_ca_libhandle) return;
+
+ /* check index */
+ if (i<0) return;
+ if (i>=x->x_ca_nbrules) return;
+
+ /* set rule by index */
+ pdp_ca_rule_string(x, x->x_ca_rulename[i]);
+
+}
+
+
+static void pdp_ca_close(t_pdp_ca *x)
+{
+ if (x->x_ca_libhandle){
+ dlclose(x->x_ca_libhandle);
+ x->x_ca_libhandle = 0;
+ x->x_ca_routine = 0;
+ if (x->x_ca_rulename){
+ free (x->x_ca_rulename);
+ x->x_ca_rulename = 0;
+ }
+
+
+ }
+}
+
+
+static void pdp_ca_printrules(t_pdp_ca *x)
+{
+ int i;
+
+ if (!(x->x_ca_libhandle)) return;
+ post("pdp_ca: found %d rules: ", x->x_ca_nbrules);
+ for(i=0;i<x->x_ca_nbrules; i++) post("%3d: %s ", i, x->x_ca_rulename[i]);
+
+
+}
+
+static void pdp_ca_open(t_pdp_ca *x, t_symbol *s)
+{
+
+ char *c;
+ int words;
+
+ /* close current lib, if one */
+ pdp_ca_close(x);
+
+ /* try to open new lib */
+ if (!(x->x_ca_libhandle = dlopen(s->s_name, RTLD_NOW))){
+ post("pdp_ca: can't open ca library %s, %s", s->s_name, dlerror());
+ x->x_ca_libhandle = 0;
+ }
+
+ /* scan for valid rules */
+ if (!(x->x_ca_rulenames = (char *)dlsym(x->x_ca_libhandle, "rulenames"))){
+ post("pdp_ca: ERROR: %s does not contain a name table. closing.", s->s_name);
+ pdp_ca_close(x);
+ return;
+ }
+
+ /* count rules */
+ words = 0;
+ for(c = (char *)x->x_ca_rulenames; *c;){
+ words++;
+ while(*c++);
+ }
+ x->x_ca_nbrules = words;
+ x->x_ca_rulename = (char **)malloc(sizeof(char *) * words);
+
+ /* build name array */
+ words = 0;
+ for(c = (char *)x->x_ca_rulenames; *c;){
+ x->x_ca_rulename[words] = c;
+ words++;
+ while(*c++);
+ }
+
+ /* ok, we're done */
+ post("pdp_ca: opened rule library %s", s->s_name ,x->x_ca_nbrules);
+
+ /* print rule names */
+ //pdp_ca_printrules(x);
+
+
+
+}
+
+/* init the current packet with random noise */
+static void pdp_ca_rand(t_pdp_ca *x){
+
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+ int i;
+
+ int nbshortints = (pdp_type_ca_info(header)->width >> 4) * pdp_type_ca_info(header)->height;
+
+ for(i=0; i<nbshortints; i++)
+ data[i] = random();
+
+}
+
+
+static void pdp_ca_newca(t_pdp_ca *x, t_float width, t_float height)
+{
+ int w = (int)width;
+ int h = (int)height;
+ int bytesize;
+ t_pdp *header;
+
+ /* ensure with = multiple of 64 */
+ w &= 0xffffffc0;
+
+ /* ensure height = multiple of 4 */
+ w &= 0xfffffffc;
+
+ w = (w<64) ? 64 : w;
+ h = (h<4) ? 4 : h;
+
+ bytesize = (w>>3) * h;
+
+ /* delete old packets */
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+
+
+ /* create new packets */
+ x->x_packet0 = pdp_packet_new(PDP_CA, bytesize);
+ header = pdp_packet_header(x->x_packet0);
+ pdp_type_ca_info(header)->encoding = PDP_CA_STANDARD;
+ pdp_type_ca_info(header)->width = w;
+ pdp_type_ca_info(header)->height = h;
+ pdp_type_ca_info(header)->offset = 0;
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+
+
+ /* fill with a test pattern */
+ if(0)
+ {
+ unsigned int *d;
+ int i, s;
+
+ s = (w * h) >> 5;
+
+ /* fill the first packet with 01 */
+ d = (unsigned int *)pdp_packet_data(x->x_packet0);
+ for (i=0; i<s; i++){
+ d[i] = i;
+ }
+
+ /* fill the second packet with 10 */
+ d = (unsigned int *)pdp_packet_data(x->x_packet1);
+ for (i=0; i<s; i++){
+ d[i] = i^-1;
+ }
+
+
+
+ }
+
+
+ /* fill with random noise */
+ pdp_ca_rand(x);
+
+}
+
+
+static void pdp_ca_iterations(t_pdp_ca *x, t_float f)
+{
+ int i = (int)f;
+
+ if (i < 0) i = 0;
+
+ x->x_iterations = i;
+}
+
+static void pdp_ca_free(t_pdp_ca *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_ca_close(x);
+ free(x->x_data);
+}
+
+
+
+void *pdp_ca_new(void)
+{
+ t_pdp_ca *x = (t_pdp_ca *)pd_new(pdp_ca_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("iterations"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ x->x_data = (t_pdp_ca_data *)malloc(sizeof(t_pdp_ca_data));
+ x->x_ca_routine = 0;
+ x->x_ca_libhandle = 0;
+ x->x_ca_rulename = 0;
+
+ pdp_ca_newca(x, 64, 64);
+ pdp_ca_iterations(x, 1);
+
+ x->x_packet_type = gensym("grey");
+
+ return (void *)x;
+}
+
+
+// *********************** CA CONVERTER CLASSES STUFF *********************
+// TODO: move this to a separate file later together with other converters (part of system?)
+
+#define PDP_CA2IMAGE 1
+#define PDP_IMAGE2CA 2
+
+typedef struct pdp_ca_conv_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+
+ int x_threshold;
+
+ int x_packet;
+
+ t_outlet *x_outlet0;
+
+ /* solve identity crisis */
+ int x_whoami;
+
+ /* output packet type */
+ /* only greyscale for now */
+ t_symbol *x_packet_type;
+
+} t_pdp_ca_conv;
+
+/* hot packet inlet */
+static void pdp_ca_conv_input_0(t_pdp_ca_conv *x, t_symbol *s, t_floatarg f)
+{
+ int packet = -1;
+
+ if (s == gensym("register_ro")){
+ pdp_packet_mark_unused(x->x_packet);
+ x->x_packet = pdp_packet_copy_ro((int)f);
+ return;
+ }
+ else if (s == gensym("process")){
+ switch(x->x_whoami){
+ case PDP_CA2IMAGE:
+ packet = pdp_type_ca2grey(x->x_packet);
+ break;
+ case PDP_IMAGE2CA:
+ packet = pdp_type_grey2ca(x->x_packet, x->x_threshold);
+ break;
+ }
+
+ /* throw away the original packet */
+ pdp_packet_mark_unused(x->x_packet);
+ x->x_packet = -1;
+
+ /* unregister the freshly created packet */
+ pdp_packet_mark_unused(packet);
+
+ /* output if valid */
+ if (-1 != packet) outlet_pdp(x->x_outlet0, packet);
+ }
+
+
+}
+
+void pdp_ca_conv_free(t_pdp_ca_conv *x)
+{
+ pdp_packet_mark_unused(x->x_packet);
+}
+
+
+void pdp_image2ca_threshold(t_pdp_ca_conv *x, t_float f)
+{
+ f *= 0x8000;
+
+ if (f < -0x7fff) f = -0x7fff;
+ if (f > 0x7fff) f = 0x7fff;
+
+ x->x_threshold = (short int)f;
+}
+
+void *pdp_ca2image_new(void)
+{
+ t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_ca2image_class);
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet_type = gensym("grey");
+ x->x_packet = -1;
+ x->x_whoami = PDP_CA2IMAGE;
+ return (void *)x;
+}
+
+void *pdp_image2ca_new(void)
+{
+ t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_image2ca_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("threshold"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet_type = gensym("grey");
+ x->x_packet = -1;
+ x->x_whoami = PDP_IMAGE2CA;
+ x->x_threshold = 0x4000;
+ return (void *)x;
+}
+
+
+// *********************** CLASS SETUP FUNCTIONS *********************
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_ca2image_setup(void)
+{
+ pdp_ca2image_class = class_new(gensym("pdp_ca2image"), (t_newmethod)pdp_ca2image_new,
+ (t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
+ class_addmethod(pdp_ca2image_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+}
+
+void pdp_image2ca_setup(void)
+{
+ pdp_image2ca_class = class_new(gensym("pdp_image2ca"), (t_newmethod)pdp_image2ca_new,
+ (t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
+ class_addmethod(pdp_image2ca_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_image2ca_class, (t_method)pdp_image2ca_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+}
+
+void pdp_ca_setup(void)
+{
+
+
+ pdp_ca_class = class_new(gensym("pdp_ca"), (t_newmethod)pdp_ca_new,
+ (t_method)pdp_ca_free, sizeof(t_pdp_ca), 0, A_NULL);
+
+
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_iterations, gensym("iterations"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_printrules, gensym("rules"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_rand, gensym("random"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("ca"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_close, gensym("close"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule, gensym("rule"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule_index, gensym("ruleindex"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/scaf/pdp/pdp_ca_system.c b/scaf/pdp/pdp_ca_system.c
new file mode 100644
index 0000000..0800380
--- /dev/null
+++ b/scaf/pdp/pdp_ca_system.c
@@ -0,0 +1,228 @@
+/*
+ * Cellular Automata Extension Module for pdp - Main system code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "pdp_ca.h"
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* check if packet is a valid ca packet */
+int pdp_type_isvalid_ca(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ if (!header) return 0;
+ if (PDP_CA != header->type) return 0;
+ if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return 0;
+
+ return 1;
+}
+
+/* convert a CA packet to greyscale */
+
+inline void _pdp_type_ca2grey_convert_word(unsigned short int source, short int *dest)
+{
+
+ int i;
+ for (i = 15; i>=0; i--){
+ dest[i] = ((unsigned short)(((short int)(source & 0x8000)) >> 14)) >> 1;
+ source <<= 1;
+ }
+}
+
+int pdp_type_ca2grey(int packet)
+{
+ int w, h, s, x, y, srcindex;
+ long long offset, xoffset, yoffset;
+ short int *dest;
+ unsigned short int *source;
+ t_pdp *header;
+ t_pdp *newheader;
+ int newpacket;
+ if (!(pdp_type_isvalid_ca(packet))) return -1;
+
+ header = pdp_packet_header(packet);
+ w = pdp_type_ca_info(header)->width;
+ h = pdp_type_ca_info(header)->height;
+ s = w*h;
+ source = (unsigned short int *)pdp_packet_data(packet);
+ offset = pdp_type_ca_info(header)->offset;
+ yoffset = (offset / w) * w;
+ xoffset = offset % w;
+
+ //post("pdp_type_ca2grey: offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
+
+ newpacket = pdp_packet_new(PDP_IMAGE, s<<1);
+ newheader = pdp_packet_header(newpacket);
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+ newheader->info.image.encoding = PDP_IMAGE_GREY;
+ dest = (short int *)pdp_packet_data(newpacket);
+
+
+#define check_srcindex \
+if (srcindex >= (s >> 4)) post ("pdp_type_ca2grey: srcindex out of bound");
+
+#define check_dstindex \
+if ((x+y) >= s) post ("pdp_type_ca2grey: dstindex out of bound");
+
+
+ /* dont' shift offset */
+ if (0){
+ for(y=0; y< (h*w); y+=w){
+ for(x=0; x<w; x+=16){
+ _pdp_type_ca2grey_convert_word (source[(x+y)>>4], &dest[x+y]);
+ }
+ }
+ return newpacket;
+ }
+
+
+ /* create top left */
+ for (y=0; y < (h*w) - yoffset; y+=w) {
+ for (x=0; x< (w - xoffset); x+=16) {
+ srcindex = (x+xoffset + y+yoffset) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+ /* create top right */
+ for (y=0; y < (h*w) - yoffset; y+=w) {
+ for (x = (w - xoffset); x < w; x+=16) {
+ srcindex = (x+xoffset-w + y+yoffset) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+ /* create bottom left */
+ for (y=(h*w) - yoffset; y < h*w; y+=w) {
+ for (x=0; x< (w - xoffset); x+=16) {
+ srcindex = (x+xoffset + y+yoffset-(w*h)) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+ /* create bottom right */
+ for (y=(h*w) - yoffset; y < h*w; y+=w) {
+ for (x = (w - xoffset); x < w; x+=16) {
+ srcindex = (x+xoffset-w + y+yoffset-(w*h)) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+
+ return newpacket;
+
+}
+
+
+inline unsigned short int _pdp_type_grey2ca_convert_word(short int *src, short int threshold)
+{
+ short int tmp;
+ short int dest = 0;
+ int i;
+
+ for (i = 15; i >= 0; i--){
+ dest <<= 1;
+ dest |= (src[i] > threshold);
+ }
+
+ return dest;
+}
+
+
+
+int pdp_type_grey2ca(int packet, short int threshold)
+{
+ int w, h, s, x, y, srcindex;
+ long long offset, xoffset, yoffset;
+ short int *dest;
+ short int *source;
+ t_pdp *header;
+ t_pdp *newheader;
+ int newpacket;
+ if (!(pdp_type_isvalid_image(packet))) return -1;
+
+ header = pdp_packet_header(packet);
+ w = header->info.image.width;
+ h = header->info.image.height;
+ s = w*h;
+ source = (unsigned short int *)pdp_packet_data(packet);
+
+ if ( (PDP_IMAGE_GREY != header->info.image.encoding)
+ && (PDP_IMAGE_YV12 != header->info.image.encoding)) return -1;
+
+ newpacket = pdp_packet_new(PDP_CA, s>>3);
+ newheader = pdp_packet_header(newpacket);
+ pdp_type_ca_info(newheader)->width = w;
+ pdp_type_ca_info(newheader)->height = h;
+ pdp_type_ca_info(newheader)->encoding = PDP_CA_STANDARD;
+ pdp_type_ca_info(newheader)->offset = 0;
+
+ dest = (short int *)pdp_packet_data(newpacket);
+
+ for(y=0; y< (h*w); y+=w){
+ for(x=0; x<w; x+=16){
+ dest[(x+y)>>4] = _pdp_type_grey2ca_convert_word (&source[x+y], threshold);
+ }
+ }
+ return newpacket;
+
+
+}
+
+/* returns a pointer to the ca subheader given the pdp header */
+t_ca *pdp_type_ca_info(t_pdp *x){return (t_ca *)(&x->info.raw);}
+
+
+void pdp_ca_setup(void);
+void pdp_ca2image_setup(void);
+void pdp_image2ca_setup(void);
+
+
+void pdp_scaf_setup(void)
+{
+ /* babble */
+ post ("PDP: pdp_scaf extension lib (mmx version)");
+
+ /* setup modules */
+ pdp_ca_setup();
+ pdp_ca2image_setup();
+ pdp_image2ca_setup();
+
+}
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/scaf/system/Makefile b/scaf/system/Makefile
new file mode 100644
index 0000000..2a07f4f
--- /dev/null
+++ b/scaf/system/Makefile
@@ -0,0 +1,21 @@
+all: scaf_feeder.o
+
+test: scaf_feeder_test
+
+OBJ = scaf_feeder_test.o scaf_feeder.o
+
+
+scaf_feeder_test: $(OBJ)
+ gcc -o scaf_feeder_test *.o -g -ldl
+
+.s.o:
+ as -o $*.o $*.s
+
+.c.o:
+ gcc -c $*.c -o $*.o -g
+
+clean:
+ rm -f *~
+ rm -f *.o
+ rm -f scaf_feeder_test
+
diff --git a/scaf/system/kernel.scaf b/scaf/system/kernel.scaf
new file mode 100644
index 0000000..0bc2788
--- /dev/null
+++ b/scaf/system/kernel.scaf
@@ -0,0 +1,130 @@
+( Pure Data Packet - scaforth kernel. )
+( Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> )
+( )
+( This program is free software; you can redistribute it and/or modify )
+( it under the terms of the GNU General Public License as published by )
+( the Free Software Foundation; either version 2 of the License, or )
+( [at your option] any later version. )
+( )
+( This program is distributed in the hope that it will be useful, )
+( but WITHOUT ANY WARRANTY; without even the implied warranty of )
+( MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the )
+( GNU General Public License for more details. )
+( )
+( You should have received a copy of the GNU General Public License )
+( along with this program; if not, write to the Free Software )
+( Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. )
+
+
+
+
+
+( this file contains the inline words in the scaforth kernel. )
+( when a file is compiled to asm, it will consist of word )
+( definition asm routines, macros and jmp call ret instructions. )
+( )
+( all words in this file are defined in terms of asm macros )
+( defined in scafmacros.s )
+
+
+
+( stack manip words )
+
+: over dup dropover ;
+
+( neighbourhood cell fetch words )
+
+: @-+ dup dropldTL ;
+: @0+ dup dropldTM ;
+: @++ dup dropldTR ;
+: @-0 dup dropldML ;
+: @00 dup dropldMM ;
+: @+0 dup dropldMR ;
+: @-- dup dropldBL ;
+: @0- dup dropldBM ;
+: @+- dup dropldBR ;
+
+( boolean logic )
+
+: or overor nip ;
+: xor overxor nip ;
+: and overand nip ;
+
+( binary constant loading )
+
+: 1 dup dropone ;
+: 0 dup dropzero ;
+
+( 4,3,2,1 bit add stack to register, leave carry on stack )
+
+: ++++ adb0 adb1 adb2 adb3 ;
+: +++ adb0 adb1 adb2 ;
+: ++ adb0 adb1 ;
+: + adb0 ;
+
+( 4,3,2 bit shifted 1 add )
+
+: ++++<<1 adb1 adb2 adb3 ;
+: +++<<1 adb1 adb2 ;
+: ++<<1 adb1 ;
+
+( 4,3 bit shifted 2 add )
+
+: ++++<<2 adb2 adb3 ;
+: +++<<2 adb2 ;
+
+( 4 bit shifted 3 add )
+
+: ++++<<3 adb3 ;
+
+( 4 bit accumulator access )
+
+: !a0 dupsta0 drop ;
+: !a1 dupsta1 drop ;
+: !a2 dupsta2 drop ;
+: !a3 dupsta3 drop ;
+
+: @a0 dup droplda0 ;
+: @a1 dup droplda1 ;
+: @a2 dup droplda2 ;
+: @a3 dup droplda3 ;
+
+( 4,3,2,1 bit accumulator zero tests )
+
+: ?anz dup dropisnonzero4 ;
+: ?anz4 dup dropisnonzero4 ;
+: ?anz3 dup dropisnonzero3 ;
+: ?anz2 dup dropisnonzero2 ;
+: ?anz1 dup dropisnonzero1 ;
+
+( load constants into accumulator )
+
+: a0 a0000 ;
+: a-0 a0000 ;
+: a+0 a0000 ;
+: a+1 a0001 ;
+: a+2 a0010 ;
+: a+3 a0011 ;
+: a+4 a0100 ;
+: a+5 a0101 ;
+: a+6 a0110 ;
+: a+7 a0111 ;
+
+: a+8 a1000 ;
+: a+9 a1001 ;
+: a+10 a1010 ;
+: a+11 a1011 ;
+: a+12 a1100 ;
+: a+13 a1101 ;
+: a+14 a1110 ;
+: a+15 a1111 ;
+
+: a-8 a1000 ;
+: a-7 a1001 ;
+: a-6 a1010 ;
+: a-5 a1011 ;
+: a-4 a1100 ;
+: a-3 a1101 ;
+: a-2 a1110 ;
+: a-1 a1111 ;
+
diff --git a/scaf/system/optim.rules b/scaf/system/optim.rules
new file mode 100644
index 0000000..282caf4
--- /dev/null
+++ b/scaf/system/optim.rules
@@ -0,0 +1,74 @@
+# Pure Data Packet - scaf optimization rules.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+# this file contains scaf source optimization rules for scaf compiler
+# applied after kernel word inlining and before compilation to asm
+
+# one rule that's not in here, and is the responsability for the
+# final compilation step: "word ;" is "jmp word" instead of "call word ret"
+
+# TODO: think about order!
+
+# no discrimination between pre inline and post inline optimization ops yet
+
+# pre inline optimizations
+
+"over xor" -> "overxor"
+"over and" -> "overand"
+"over or" -> "overor"
+
+"drop 1" -> "dropone"
+"drop 0" -> "dropzero"
+"over add" -> "overadd"
+"over addc" -> "overaddc"
+
+"dup !a0" -> "dupsta0"
+"dup !a1" -> "dupsta1"
+"dup !a2" -> "dupsta2"
+"dup !a3" -> "dupsta3"
+
+"drop @a0" -> "droplda0"
+"drop @a1" -> "droplda1"
+"drop @a2" -> "droplda2"
+"drop @a3" -> "droplda3"
+
+"drop ?anz" -> "dropisnonzero4"
+"drop ?anz4" -> "dropisnonzero4"
+"drop ?anz3" -> "dropisnonzero3"
+"drop ?anz2" -> "dropisnonzero2"
+"drop ?anz1" -> "dropisnonzero1"
+
+"drop @-+" -> "dropldTL"
+"drop @0+" -> "dropldTM"
+"drop @++" -> "dropldTR"
+"drop @-0" -> "dropldML"
+"drop @00" -> "dropldMM"
+"drop @+0" -> "dropldMR"
+"drop @--" -> "dropldBL"
+"drop @0-" -> "dropldBM"
+"drop @+-" -> "dropldBR"
+
+
+# post inline optimizations
+
+"dup drop" -> ""
+"swap drop" -> "nip"
+"dup swap" -> "dup"
+"drop dup" -> "dropdup"
+"drop over" -> "dropover"
+"nip dup" -> "nipdup"
diff --git a/scaf/system/scaf_feeder.s b/scaf/system/scaf_feeder.s
new file mode 100644
index 0000000..1cd8fd3
--- /dev/null
+++ b/scaf/system/scaf_feeder.s
@@ -0,0 +1,49 @@
+# Pure Data Packet - scaf feeder routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+.include "scafmacro.s"
+
+
+# *rg is only used for returning the stack pointer
+# the 4 bit counter is using registers mm4-mm7 now
+# long long scaf_feeder(void *tos, void *rg, *void() ca_rule, void *env)
+.globl scaf_feeder
+.type scaf_feeder, @function
+scaf_feeder:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 20(%ebp), %edi # load env ptr
+ movl 8(%ebp), %esi # load TOS2 ptr
+ movl 16(%ebp), %eax # address of ca routine
+ pcmpeqw %mm3, %mm3 # load 1 reg
+
+ call *%eax # TOS = 32x2 cell result
+ dup # push %mm0 to memory
+ movl (%esi), %eax
+ movl 4(%esi), %edx
+ lea 16(%esi), %esi # discard stack
+ movl %esi, (%edi) # store for stack underflow check
+
+ emms
+ pop %edi
+ pop %esi
+ leave
+ ret
diff --git a/scaf/system/scaf_feeder_test.c b/scaf/system/scaf_feeder_test.c
new file mode 100644
index 0000000..23a2661
--- /dev/null
+++ b/scaf/system/scaf_feeder_test.c
@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+
+void scaf_feeder_asm (void *tos, void *reg, void (*ca_rule)(), void *env);
+
+void ca_test() {}
+
+main()
+{
+ int stack[256];
+ int reg[8];
+ int env[8];
+
+ void *libhandle;
+ void *ca_routine;
+
+
+ if (!(libhandle = dlopen("../modules/test.scafo", RTLD_NOW))){
+ printf("error: %s\n", dlerror());
+ exit(1);
+ }
+
+ if (!(ca_routine = dlsym(libhandle, "carule_1"))){
+ printf("error: %s\n", dlerror());
+ exit(1);
+ }
+
+ scaf_feeder_asm(stack+254, reg, ca_routine, env);
+
+ dlclose(libhandle);
+}
diff --git a/scaf/system/scafc.pl b/scaf/system/scafc.pl
new file mode 100755
index 0000000..ee6b969
--- /dev/null
+++ b/scaf/system/scafc.pl
@@ -0,0 +1,269 @@
+#!/usr/bin/perl
+
+# Pure Data Packet - scafc: scaf compiler.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# set this if you want to enable/disable optimizing
+
+$optimize = 1;
+
+
+# this parses a single scaf line
+# it is not very intelligent. only looks for 1 def on a line
+# todo: change later so it can read multiple lines
+
+
+sub remove_illegal_characters {
+ my $line = shift;
+ $$line =~ s/\+/_PLUS_/g;
+ $$line =~ s/-/_MINUS_/g;
+ $$line =~ s/\@/_AT_/g;
+ $$line =~ s/:/_COLON_/g;
+ $$line =~ s/\?/_QMARK_/g;
+ $$line =~ s/<</_SHIFT_/g;
+ $$line =~ s/</_ST_/g;
+ $$line =~ s/>/_GT_/g;
+ $$line =~ s/=/_EQ_/g;
+ $$line =~ s/\(/_OPEN_/g;
+ $$line =~ s/\)/_CLOSE_/g;
+}
+
+sub parse_scaf_line {
+ my $word, $def, $sub;
+ shift;
+
+ # this transforms the source into a parsed assembly like form
+ # a word label: "<word>:<ret>"
+ # a word definition line "<tab><word><ret>"
+ # last def = <ret><ret>
+
+ # dont process if line doesn't have a def
+
+ # first remove comments
+ s/\(\s+(\S+\s+)*?\)//g;
+
+ if (m/:\s+/){
+
+ # separate word and definition
+ m/:\s+(\S+)\s+(.*)/;
+ $word = $1;
+ $def = $2;
+
+ # remove illegal characters;
+ remove_illegal_characters \$word;
+ remove_illegal_characters \$def;
+
+ # format definition in asm style
+ $def =~ s/(\S+)(\s*)/\t$1\n/g;
+
+ # replace ; by r
+ $def =~ s/\s+;\s*/\n\tr\n/;
+
+ # put word: def into one string
+ $sub = "$word:\n$def\n";
+
+ # debug
+ #$sub =~ s/\t/<tab>/g;
+ #$sub =~ s/\n/<ret>\n/g;
+ #print "$sub";
+
+ return $sub;
+
+ }
+
+};
+
+
+
+# load and parse scaf source file
+sub load_source {
+ my $filename = shift;
+ open(SOURCE, $filename) or die "Can't locate source module $filename\n";
+ my @parsedsource;
+ while (<SOURCE>){
+ my $sub = parse_scaf_line $_;
+ if ($sub) {
+ push @parsedsource, ($sub);
+ }
+
+ }
+ close(SOURCE);
+ return @parsedsource;
+
+}
+
+# this routine parses the optimization rules
+sub load_optim {
+ my $filename = shift;
+ open(OPTIM, $filename) or die "Can't locate optimization rule file $filename\n";
+ my @parsedoptim;
+ while (<OPTIM>){
+ unless (m/\A\#/){
+
+ if (m/\"\s*(.*?)\s*\".*?\"\s*(.*?)\s*\"/)
+ {
+ my $source = $1;
+ my $dest = $2;
+
+ $source =~ s/\s+/\n\t/;
+ $dest =~ s/\s+/\n\t/;
+ $source = "\t$source\n";
+ $dest = "\t$dest\n";
+
+ remove_illegal_characters \$source;
+ remove_illegal_characters \$dest;
+
+ push @parsedoptim, ("$source:$dest");
+ }
+ }
+ }
+ close(OPTIM);
+
+ return @parsedoptim;
+
+
+}
+
+
+
+# inline one parsed source's definitions into another parsed source's
+sub inline_defs {
+ my $dest = shift;
+ my $source = shift;
+
+ #print @$dest;
+ #print @$source;
+
+
+ # loop over file with inline defs
+ foreach (@$source) {
+ #print "<SUB>$_</SUB>\n";
+ m/(\S+):\n(.*)\tr\n/s;
+
+ my $def = "\t$1\n";
+ my $body = $2;
+
+ #print "<DEF>$def</DEF>\n";
+ #print "<BODY>$body</BODY>\n";
+
+ foreach (@$dest) {
+ s/$def/$body/g;
+ }
+
+ }
+
+}
+
+# this changes <WORD> to c <WORD> or j <WORD> all defined words
+# the undefined words are supposed to be asm macros
+sub call_defs {
+ my $dest = shift;
+
+ foreach (@$dest){
+ m/(\S+):\n/s;
+ my $word = $1;
+ foreach (@$dest){
+ s/\t$word\n\tr\n/\tj $word\n/sg;
+ s/\t$word\n/\tc $word\n/sg;
+ }
+ }
+}
+
+# substitue word sequences in dest using optim table
+sub subst_optim {
+ my $dest = shift;
+ my $optim = shift;
+ foreach (@$optim){
+ m/(.*?):(.*)/s;
+ my $key = $1;
+ my $subst = $2;
+
+ foreach (@$dest){
+ s/$key/$subst/sg;
+ }
+ }
+}
+
+# add directives to produce global symbols
+# global symbols need to start with carule_
+sub global_syms {
+ my $source = shift;
+ foreach (@$source){
+ s/rule_(\S+):\n/.globl\trule_$1\n.type\trule_$1,\@function\nrule_$1:\n/sg;
+ }
+}
+
+# create an array with names for bookkeeping
+sub name_array {
+ my @namearray;
+ my $source = shift;
+ push @namearray, (".globl rulenames\nrulenames:\n");
+ foreach (@$source){
+ if (m/rule_(\S+):/s){
+ push @namearray, (".asciz\t\"$1\"\n");
+ }
+ }
+ push @namearray, (".byte\t0\n");
+ return @namearray;
+
+}
+
+# main program body
+
+$dir=".";
+
+$source = "-";
+
+
+# parse command line
+foreach (@ARGV){
+ if (m/-I(.*)/) {
+ $dir = $1;
+ }
+ else {
+ $source = $_;
+ }
+}
+
+$kernel = "$dir/kernel.scaf";
+$macro = "$dir/scafmacro.s";
+$rules = "$dir/optim.rules";
+
+
+
+# load files
+@psource = load_source $source;
+@pkernel = load_source $kernel;
+@poptim = load_optim $rules;
+
+
+# substitute kernel defs in source
+if ($optimize) {subst_optim \@psource, \@poptim;}
+inline_defs \@psource, \@pkernel;
+
+if ($optimize) {subst_optim \@psource, \@poptim;}
+
+call_defs \@psource;
+global_syms \@psource;
+@pnames = name_array \@psource;
+
+# print out asm file
+print ".include \"$macro\"\n\n";
+print @psource;
+print @pnames;
+
diff --git a/scaf/system/scafmacro.s b/scaf/system/scafmacro.s
new file mode 100644
index 0000000..04e6537
--- /dev/null
+++ b/scaf/system/scafmacro.s
@@ -0,0 +1,487 @@
+ # Pure Data Packet - scaf assembler macros.
+ # Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ #
+
+
+ # this file contains pure asm macros. it is to be included before assembly
+ # after scaforth.pl has processed the .scaf file
+
+ # *************************** JMP CALL RET **************************************
+ # j c r
+
+ .macro j address
+ jmp \address
+ .endm
+
+ .macro c address
+ call \address
+ .endm
+
+ .macro r
+ ret
+ .endm
+
+
+ # *************************** CA CELL ACCESS MACROS *****************************
+ # dropldTL - dropldBR
+
+ # shift / load rectangle macros:
+
+ # shift rectangle horizontal
+ # result is in reg1
+ .macro shift reg1 reg2 count
+ psllq $(16-\count), \reg1
+ psrlq $(16+\count), \reg2
+ psrlq $32, \reg1
+ psllq $32, \reg2
+ por \reg2, \reg1
+ .endm
+
+ .macro ldtop reg1 reg2
+ movq (%edi), \reg1
+ movq 8(%edi), \reg2
+ .endm
+
+ .macro ldcenter reg1 reg2
+ movq 8(%edi), \reg1
+ movq 16(%edi), \reg2
+ .endm
+
+ .macro ldbottom reg1 reg2
+ movq 16(%edi), \reg1
+ movq 24(%edi), \reg2
+ .endm
+
+
+ # dropld from top row
+
+ # dropld the top left square
+ .macro dropldTL
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # dropld the top mid square
+ .macro dropldTM
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # dropld the top right square
+ .macro dropldTR
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+ # dropld from center row
+
+ # dropld the mid left square
+ .macro dropldML
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # dropld the mid mid square
+ .macro dropldMM
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # dropld the mid right square
+ .macro dropldMR
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+
+
+ # dropld from bottom row
+
+ # dropld the bottom left square
+ .macro dropldBL
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # dropld the bottom mid square
+ .macro dropldBM
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # dropld the bottom right square
+ .macro dropldBR
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+ # *************************** CA STACK MANIP MACROS *****************************
+ # these are the only asm macros that have a stack effect other than
+ # just replacing the TOS
+ #
+ # dup drop dropdup swap nip dropover
+
+ .macro dup
+ lea -8(%esi), %esi
+ movq %mm0, (%esi)
+ .endm
+
+ .macro drop
+ movq (%esi), %mm0
+ lea 8(%esi), %esi
+ .endm
+
+ .macro dropdup
+ movq (%esi), %mm0
+ .endm
+
+ .macro nipdup
+ movq %mm0, (%esi)
+ .endm
+
+ .macro swap
+ movq (%esi), %mm1
+ movq %mm0, (%esi)
+ movq %mm1, %mm0
+ .endm
+
+ .macro nip
+ lea 8(%esi), %esi
+ .endm
+
+ .macro dropover
+ movq 8(%esi), %mm0
+ .endm
+
+
+ # *************************** CA BOOLEAN LOGIC MACROS *****************************
+ # overxor overand overor not
+
+ .macro overxor
+ pxor (%esi), %mm0
+ .endm
+
+ .macro overand
+ pand (%esi), %mm0
+ .endm
+
+ .macro overor
+ por (%esi), %mm0
+ .endm
+
+ .macro not
+ pxor %mm3, %mm0
+ .endm
+
+
+
+ # *************************** CONSTANTS *****************************
+ # dropzero dropone
+
+ .macro dropzero
+ pxor %mm0, %mm0
+ .endm
+
+ .macro dropone
+ pcmpeqw %mm0, %mm0
+ .endm
+
+
+ # *************************** 4 BIT REG ACCESS ******************************
+ # dupsta0 - dupsta4 droplda0 - droplda4
+ # store bit in accumulator
+
+ # bit store
+
+ .macro dupsta0
+ movq %mm0, %mm4
+ .endm
+
+ .macro dupsta1
+ movq %mm0, %mm5
+ .endm
+
+ .macro dupsta2
+ movq %mm0, %mm6
+ .endm
+
+ .macro dupsta3
+ movq %mm0, %mm7
+ .endm
+
+ # load bit from accumulator
+
+ .macro droplda0
+ movq %mm4, %mm0
+ .endm
+
+ .macro droplda1
+ movq %mm5, %mm0
+ .endm
+
+ .macro droplda2
+ movq %mm6, %mm0
+ .endm
+
+ .macro droplda3
+ movq %mm7, %mm0
+ .endm
+
+
+ # *************************** LOAD 4 BIT CONSTANT IN REG ******************************
+ # a0000 - a1111
+
+ .macro ldbit0 value
+ .ifeq \value
+ movq %mm1, %mm4
+ .else
+ movq %mm3, %mm4
+ .endif
+ .endm
+
+ .macro ldbit1 value
+ .ifeq \value
+ movq %mm1, %mm5
+ .else
+ movq %mm3, %mm5
+ .endif
+ .endm
+
+ .macro ldbit2 value
+ .ifeq \value
+ movq %mm1, %mm6
+ .else
+ movq %mm3, %mm6
+ .endif
+ .endm
+
+ .macro ldbit3 value
+ .ifeq \value
+ movq %mm1, %mm7
+ .else
+ movq %mm3, %mm7
+ .endif
+ .endm
+
+ .macro ldbin b3 b2 b1 b0
+ pxor %mm1, %mm1
+ ldbit0 \b0
+ ldbit1 \b1
+ ldbit2 \b2
+ ldbit3 \b3
+ .endm
+
+ .macro a0000
+ ldbin 0 0 0 0
+ .endm
+
+ .macro a0001
+ ldbin 0 0 0 1
+ .endm
+
+ .macro a0010
+ ldbin 0 0 1 0
+ .endm
+
+ .macro a0011
+ ldbin 0 0 1 1
+ .endm
+
+ .macro a0100
+ ldbin 0 1 0 0
+ .endm
+
+ .macro a0101
+ ldbin 0 1 0 1
+ .endm
+
+ .macro a0110
+ ldbin 0 1 1 0
+ .endm
+
+ .macro a0111
+ ldbin 0 1 1 1
+ .endm
+
+ .macro a1000
+ ldbin 1 0 0 0
+ .endm
+
+ .macro a1001
+ ldbin 1 0 0 1
+ .endm
+
+ .macro a1010
+ ldbin 1 0 1 0
+ .endm
+
+ .macro a1011
+ ldbin 1 0 1 1
+ .endm
+
+ .macro a1100
+ ldbin 1 1 0 0
+ .endm
+
+ .macro a1101
+ ldbin 1 1 0 1
+ .endm
+
+ .macro a1110
+ ldbin 1 1 1 0
+ .endm
+
+ .macro a1111
+ ldbin 1 1 1 1
+ .endm
+
+
+
+
+ # *************************** 4 BIT COUNTER ******************************
+ # adds TOS to bit of counter and returns carry in TOS
+ #
+ # adb0 - adb3
+
+
+ .macro adb0
+ movq %mm4, %mm2
+ pxor %mm0, %mm4
+ pand %mm2, %mm0
+ .endm
+
+ .macro adb1
+ movq %mm5, %mm2
+ pxor %mm0, %mm5
+ pand %mm2, %mm0
+ .endm
+
+ .macro adb2
+ movq %mm6, %mm2
+ pxor %mm0, %mm6
+ pand %mm2, %mm0
+ .endm
+
+ .macro adb3
+ movq %mm7, %mm2
+ pxor %mm0, %mm7
+ pand %mm2, %mm0
+ .endm
+
+
+ # *************************** ACCUMULATOR TESTS ***************************
+ # dropisnonzero4 - dropisnonzero1
+
+ .macro dropisnonzero4
+ movq %mm4, %mm0
+ por %mm5, %mm0
+ por %mm6, %mm0
+ por %mm7, %mm0
+ .endm
+
+ .macro dropisnonzero3
+ movq %mm4, %mm0
+ por %mm5, %mm0
+ por %mm6, %mm0
+ .endm
+
+ .macro dropisnonzero2
+ movq %mm4, %mm0
+ por %mm5, %mm0
+ .endm
+
+ .macro dropisnonzero1
+ movq %mm4, %mm0
+ .endm
+
+
+ # *************************** REGISTER SHIFT OPERATIONS **********************
+ # shift and leave shifted out byte on stack
+ # rotate trough top of stack
+
+ .macro dropshiftright
+ movq %mm4, %mm0
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ pxor %mm7, %mm7
+ .endm
+
+ .macro dropshiftleft
+ movq %mm7, %mm0
+ movq %mm6, %mm7
+ movq %mm5, %mm6
+ movq %mm4, %mm5
+ pxor %mm4, %mm4
+ .endm
+
+ .macro dropshiftrighta
+ movq %mm4, %mm0
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ .endm
+
+ .macro rotateright
+ movq %mm4, %mm1
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ movq %mm1, %mm7
+ .endm
+
+ .macro rotateleft
+ movq %mm7, %mm1
+ movq %mm6, %mm7
+ movq %mm5, %mm6
+ movq %mm4, %mm5
+ movq %mm1, %mm4
+ .endm
+
+ .macro rotaterightstack
+ movq %mm0, %mm1
+ movq %mm4, %mm0
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ movq %mm1, %mm7
+ .endm
+
+ .macro rotateleftstack
+ movq %mm0, %mm1
+ movq %mm7, %mm0
+ movq %mm6, %mm7
+ movq %mm5, %mm6
+ movq %mm4, %mm5
+ movq %mm1, %mm4
+ .endm
+
+ # *************************** OTHER REGISTER OPERATIONS **********************
+ # anot : complement reg (can be used to implement subtraction)
+
+ .macro anot
+ pxor %mm3, %mm4
+ pxor %mm3, %mm5
+ pxor %mm3, %mm6
+ pxor %mm3, %mm7
+ .endm
diff --git a/scaf/test/test_pdp_ca.pd b/scaf/test/test_pdp_ca.pd
new file mode 100644
index 0000000..1b84312
--- /dev/null
+++ b/scaf/test/test_pdp_ca.pd
@@ -0,0 +1,132 @@
+#N canvas 650 350 625 557 10;
+#X obj 287 82 openpanel;
+#X msg 287 56 bang;
+#X msg 288 110 open \$1;
+#X obj 230 191 pdp_ca;
+#X obj 193 76 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 223 80 metro 40;
+#X msg 211 56 bang;
+#X msg 247 56 stop;
+#X obj 146 235 pdp_xv;
+#X obj 28 31 t b b b;
+#X obj 11 7 loadbang;
+#X msg 99 80 rule id;
+#X msg 328 155 ca 256 256;
+#X msg 256 296 rule shifttopright;
+#X msg 331 134 ca 64 64;
+#X msg 262 270 rule shiftleft;
+#X msg 298 216 random;
+#X msg 251 321 rule gameoflife;
+#X floatatom 344 52 5 0 0;
+#X msg 331 184 ca 1024 1024;
+#X floatatom 279 154 5 0 0;
+#X msg 357 106 ca 512 512;
+#X msg 363 80 ca 320 240;
+#X obj 211 120 pdp_v4l;
+#X obj 179 99 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 138 53 metro 40;
+#X msg 126 29 bang;
+#X msg 162 29 stop;
+#X floatatom 205 28 5 0 0;
+#X msg 243 348 rule w110;
+#X msg 245 371 rule w110mod;
+#X msg 54 371 rule w110mod2;
+#X msg 387 47 ca 640 394;
+#X obj 481 289 count;
+#X obj 397 248 route 0 1 2 3;
+#X floatatom 517 254 5 0 0;
+#X msg 466 184 bang;
+#X msg 502 184 stop;
+#X floatatom 552 171 5 0 0;
+#X obj 478 208 metro 1000;
+#X msg 258 403 rule golmod;
+#X floatatom 34 129 5 0 0;
+#X obj 90 207 pdp_bqt;
+#X msg 62 107 dim 64 64;
+#X msg 44 167 hpf \$1 0.5;
+#X msg 272 430 rule golmod2;
+#X msg 273 467 rule golmod3;
+#X msg 277 494 rule golmod4;
+#X msg 280 515 rule golmod5;
+#X msg 283 537 rule golmod6;
+#X msg 380 403 rule golmod7;
+#X obj 46 267 pdp_mix;
+#X floatatom 120 297 5 0 0;
+#X msg 61 462 type grey;
+#X msg 112 407 rule w110mod3;
+#X msg 64 490 type yv12;
+#X msg 438 471 dim 512 512;
+#X obj 270 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 463 111 ca 1024 512;
+#X msg 105 4 open /home/tom/pd/packet/scaf/modules/carules.scafo;
+#X msg 163 468 rule toomuch;
+#X msg 165 500 rule underflow;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 3 0 8 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 9 1 11 0;
+#X connect 9 2 59 0;
+#X connect 10 0 9 0;
+#X connect 11 0 3 0;
+#X connect 12 0 3 0;
+#X connect 13 0 3 0;
+#X connect 14 0 3 0;
+#X connect 15 0 3 0;
+#X connect 16 0 3 0;
+#X connect 17 0 3 0;
+#X connect 18 0 5 1;
+#X connect 19 0 3 0;
+#X connect 20 0 3 2;
+#X connect 21 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 51 1;
+#X connect 23 0 3 1;
+#X connect 24 0 23 0;
+#X connect 25 0 24 0;
+#X connect 26 0 25 0;
+#X connect 27 0 25 0;
+#X connect 28 0 25 1;
+#X connect 29 0 3 0;
+#X connect 30 0 3 0;
+#X connect 31 0 3 0;
+#X connect 32 0 3 0;
+#X connect 33 0 34 0;
+#X connect 34 0 30 0;
+#X connect 34 1 17 0;
+#X connect 34 2 40 0;
+#X connect 34 3 17 0;
+#X connect 35 0 33 1;
+#X connect 36 0 39 0;
+#X connect 37 0 39 0;
+#X connect 38 0 39 1;
+#X connect 39 0 33 0;
+#X connect 40 0 3 0;
+#X connect 41 0 44 0;
+#X connect 42 0 8 0;
+#X connect 43 0 23 0;
+#X connect 44 0 42 0;
+#X connect 45 0 3 0;
+#X connect 46 0 3 0;
+#X connect 47 0 3 0;
+#X connect 48 0 3 0;
+#X connect 49 0 3 0;
+#X connect 50 0 3 0;
+#X connect 51 0 8 0;
+#X connect 52 0 51 2;
+#X connect 53 0 23 0;
+#X connect 54 0 3 0;
+#X connect 55 0 23 0;
+#X connect 56 0 8 0;
+#X connect 57 0 20 0;
+#X connect 58 0 3 0;
+#X connect 59 0 3 0;
+#X connect 60 0 3 0;
+#X connect 61 0 3 0;
diff --git a/scaf/test/test_pdp_ca2.pd b/scaf/test/test_pdp_ca2.pd
new file mode 100644
index 0000000..8af44a8
--- /dev/null
+++ b/scaf/test/test_pdp_ca2.pd
@@ -0,0 +1,154 @@
+#N canvas 454 152 625 557 10;
+#X obj 325 83 openpanel;
+#X msg 325 57 bang;
+#X msg 326 111 open \$1;
+#X obj 428 234 pdp_ca;
+#X obj 256 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 223 80 metro 40;
+#X msg 211 56 bang;
+#X msg 247 56 stop;
+#X obj 402 407 pdp_xv;
+#X obj 28 31 t b b b;
+#X obj 11 7 loadbang;
+#X msg 391 99 ca 256 256;
+#X msg 394 78 ca 64 64;
+#X msg 298 216 random;
+#X msg 251 321 rule gameoflife;
+#X floatatom 490 187 5 0 0;
+#X msg 420 50 ca 512 512;
+#X obj 107 188 pdp_v4l;
+#X obj 97 127 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 243 348 rule w110;
+#X msg 245 371 rule w110mod;
+#X msg 258 403 rule golmod;
+#X msg 272 430 rule golmod2;
+#X msg 273 467 rule golmod3;
+#X msg 277 494 rule golmod4;
+#X msg 280 515 rule golmod5;
+#X msg 283 537 rule golmod6;
+#X obj 481 167 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 526 55 ca 1024 512;
+#X msg 105 4 open /home/tom/pd/packet/scaf/modules/carules.scafo;
+#X obj 426 294 pdp_ca2image;
+#X obj 104 228 pdp_image2ca;
+#X obj 136 155 metro 40;
+#X msg 124 131 bang;
+#X msg 160 131 stop;
+#X floatatom 510 273 5 0 0;
+#X obj 501 253 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 468 416 rule gameoflife;
+#X msg 450 455 rule golmod6;
+#X msg 380 440 rule golmod3;
+#X msg 159 287 rules;
+#X floatatom 27 213 5 0 0;
+#X msg 40 319 ruleindex \$1;
+#X obj 31 254 t b f;
+#X msg 52 78 rule gameoflife;
+#X floatatom 193 198 5 0 0;
+#X msg 504 143 close;
+#X msg 149 448 rule test1;
+#X obj 181 178 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 5 129 dim 640 480;
+#X obj 156 51 pdp_qt;
+#X msg 174 23 open /home/ben/MOV/test1.mov;
+#X floatatom 93 31 5 0 0;
+#X msg 65 56 autoplay 1;
+#X obj 144 25 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 22 94 loop 1;
+#X obj 439 483 osc~ 150;
+#X obj 439 508 *~ 0.1;
+#X obj 437 536 dac~;
+#X floatatom 282 57 5 0 0;
+#X msg 503 113 ca 32 32;
+#X obj 428 322 pdp_motion_blur;
+#X obj 488 349 pdp_gradient;
+#X obj 425 382 pdp_mix;
+#X floatatom 508 380 5 0 0;
+#X floatatom 204 128 5 0 0;
+#X obj 39 399 pdp_control;
+#X obj 83 476 pdp_control;
+#X obj 84 519 print two;
+#X obj 39 438 print one;
+#X obj 275 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 265 128 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 38 374 thread \$1;
+#X obj 32 349 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 3 0 30 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 9 1 44 0;
+#X connect 9 2 29 0;
+#X connect 10 0 9 0;
+#X connect 11 0 3 0;
+#X connect 12 0 3 0;
+#X connect 13 0 3 0;
+#X connect 14 0 3 0;
+#X connect 15 0 3 2;
+#X connect 16 0 3 0;
+#X connect 17 0 31 0;
+#X connect 17 0 63 1;
+#X connect 18 0 17 0;
+#X connect 19 0 3 0;
+#X connect 20 0 3 0;
+#X connect 21 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 3 0;
+#X connect 24 0 3 0;
+#X connect 25 0 3 0;
+#X connect 26 0 3 0;
+#X connect 27 0 15 0;
+#X connect 28 0 3 0;
+#X connect 29 0 3 0;
+#X connect 30 0 62 0;
+#X connect 31 0 3 0;
+#X connect 32 0 17 0;
+#X connect 33 0 32 0;
+#X connect 34 0 32 0;
+#X connect 36 0 35 0;
+#X connect 40 0 3 0;
+#X connect 41 0 43 0;
+#X connect 42 0 3 0;
+#X connect 43 0 13 0;
+#X connect 43 1 42 0;
+#X connect 44 0 3 0;
+#X connect 45 0 31 1;
+#X connect 46 0 3 0;
+#X connect 47 0 3 0;
+#X connect 48 0 45 0;
+#X connect 49 0 17 0;
+#X connect 50 0 31 0;
+#X connect 51 0 50 0;
+#X connect 52 0 50 0;
+#X connect 53 0 50 0;
+#X connect 54 0 50 0;
+#X connect 55 0 50 0;
+#X connect 56 0 57 0;
+#X connect 57 0 58 0;
+#X connect 57 0 58 1;
+#X connect 59 0 5 1;
+#X connect 60 0 3 0;
+#X connect 62 0 63 0;
+#X connect 63 0 8 0;
+#X connect 64 0 63 2;
+#X connect 65 0 32 1;
+#X connect 66 0 69 0;
+#X connect 67 0 68 0;
+#X connect 70 0 3 0;
+#X connect 71 0 4 0;
+#X connect 71 0 70 0;
+#X connect 72 0 66 0;
+#X connect 73 0 72 0;