<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-21310324</id><updated>2012-01-31T18:20:10.097-08:00</updated><category term='propellerforth'/><category term='linux'/><category term='cocoa'/><category term='arm'/><category term='objective-c'/><category term='gpl'/><category term='cesta'/><category term='mongoose'/><category term='eee'/><category term='warrantyvoid'/><category term='java'/><category term='ntsc'/><category term='propeller'/><category term='compilers'/><category term='llvm'/><category term='pfcam'/><category term='rc'/><category term='proprietary'/><category term='performance'/><category term='lpc'/><category term='acer aspire one'/><category term='ubuntu'/><category term='machine learning'/><category term='hydra'/><title type='text'>Cliff Hacks Things.</title><subtitle type='html'>A blog for my tech rants.  My rants, suggestions, ideas, and general pedantry here are representative solely of this geek-at-arms, and not my employer, affiliated civic service organizations, deceased ancestors, or people whose names rhyme with my own.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>65</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-21310324.post-4833250555378125138</id><published>2010-01-29T18:17:00.000-08:00</published><updated>2010-02-15T17:28:30.585-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='arm'/><category scheme='http://www.blogger.com/atom/ns#' term='lpc'/><category scheme='http://www.blogger.com/atom/ns#' term='proprietary'/><title type='text'>LPCxpresso: nice hardware made useless by bad software</title><content type='html'>Remember back in the mid-90s, when many of us used Microchip PICs for embedded control?  Remember having to use a shoddy closed-source compiler, which only ran on one operating system/architecture?  Remember having to use a particular set of tools, instead of whatever tools you were most comfortable with?&lt;br /&gt;&lt;br /&gt;Fast-forward to 2010, and you can re-experience all these limitations with the &lt;a href="http://ics.nxp.com/lpcxpresso/"&gt;NXP LPCxpresso board&lt;/a&gt;!  This evaluation board for the NXP LPC ARM chips is...well, I'll let them speak for themselves:&lt;br /&gt;&lt;blockquote&gt;The LPCXpresso evaluation board is meant to be used only with the Code Red LPCXpresso, or Red Suite IDEs.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;This runs only on Windows, of course.  Yes, folks, it's like 1995 all over again.  &lt;strike&gt;Consensus among reverse engineers I've contacted is that the programming/debugging interface is cryptographically secured, to keep you from using it the way you want.&lt;/strike&gt; (Edit: I've decided there's not enough evidence to support this claim.)&lt;br /&gt;&lt;br /&gt;Not that Digikey tells you this before you buy, of course!  At the time of this writing, even the LPCxpresso web site makes no mention of this, unless you drill down into the PDF Getting Started Guide.  Fortunately, competing parts from both Atmel and ST Microelectronics have support for GCC and cross-platform programmers and debuggers.  I'll be using these in my next design and sending the LPCxpresso back to the factory.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; Someone claiming to be from Code Red commented below, noting that they do have GCC support, but didn't address the other points (cross-platform compatibility being the main one).  I based my initial complaints of "no command line compiler" and "no GCC support" on other users' summaries, since (not having Windows) I couldn't test that.  My bad; these claims have been removed.&lt;br /&gt;&lt;br /&gt;If Code Red does indeed provide cross-platform support (or OSS tools that could become cross-platform) I'll update this post!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; They do not, though they suggest I could run Windows in a VM.  Missing the point, guys.&lt;br /&gt;&lt;br /&gt;To be clear, I'm not a complete noob to embedded ARM systems, or Cortex-M3.  Once I decided not to return this proprietary piece of circuit (because I'm terribly stubborn), I tried putting together a toolchain based on CS2009q3, writing a linker script, soldering on a USB connector, implementing the proprietary NXP checksum algorithm, chopping off the debug circuitry that I paid for and would sure like to use, etc.  Never quite worked right - got consistent firmware corruption.  My point is that I &lt;strong&gt;shouldn't have to do any of this stuff, or troll through forums trying to decide which contradictory answer is correct.&lt;/strong&gt;  I'm currently rather enamored with the &lt;a href="http://mbed.org"&gt;mbed&lt;/a&gt; eval board, which, unlike the LPCxpresso, explicitly supports Mac and Linux out of the box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4833250555378125138?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4833250555378125138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4833250555378125138' title='78 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4833250555378125138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4833250555378125138'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2010/01/lpcxpresso-nice-hardware-made-useless.html' title='LPCxpresso: nice hardware made useless by bad software'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>78</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-6786615180415167591</id><published>2008-12-09T21:32:00.000-08:00</published><updated>2008-12-09T21:42:30.159-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='compilers'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='propeller'/><title type='text'>Linear-scan register allocator adapted</title><content type='html'>I've adapted the SSA Linear-Scan allocator, originally designed by M&amp;ouml;ssenb&amp;ouml;ck and Pfeiffer for Hotspot, for my Propeller Java compiler.&lt;br /&gt;&lt;br /&gt;It has some advantages:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;It's simple.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It's fast.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It does a pretty good job.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It can deal with destructive arithmetic ops (as in the Propeller) and pre-colored registers (as in calling conventions) easily.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Handling pre-colored registers well is particularly important to me, since I'm trying to do &lt;em&gt;all&lt;/em&gt; lowering and allocation without leaving SSA.  This includes the calling conventions.  With this algorithm, it's a matter of&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Before each call, insert extra &lt;code&gt;mov&lt;/code&gt;s to clone each argument value.  Pre-color these clone values with the appropriate registers in the calling convention.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;After each call, rewrite the return value to go into a temporary, which is pre-colored with the returned-result register, and which gets immediately &lt;code&gt;mov&lt;/code&gt;-d to the right value.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rely on the phi-equivalence coalescing algorithm (still adapted from Pereira) to merge the non-interfering values and eliminate the copies.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I've altered Pereira's algorithm to deal with the "join families" that M&amp;ouml;ssenb&amp;oml;/Pfeiffer generate.  (Arguably in doing so I've recreated &lt;em&gt;their&lt;/em&gt; coalesce algorithm, but hey.)&lt;br /&gt;&lt;br /&gt;Here's a new test function with some interfering values:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public int function(int x) {&lt;br /&gt;    int y = 1;&lt;br /&gt;    int z = 0;&lt;br /&gt;    &lt;br /&gt;    while (y &amp;lt; x) {&lt;br /&gt;      z = y;&lt;br /&gt;      y++;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return z;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here's the new output with the new register allocator and dramatically better interference analysis.  Note that I don't actually build an interference graph at any point; not sure if this is going to come back to bite me.&lt;br /&gt;&lt;br /&gt;Remember that the code runs backwards.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;method$:L27312399&lt;br /&gt;  IF_ALWAYS JMPRET prim_return_ret, #prim_return&lt;br /&gt;&lt;br /&gt;  long @method$:L27312399&lt;br /&gt;  long @method$:L11631043&lt;br /&gt;  IF_ALWAYS JMPRET prim_jmplt_ret, #prim_jmplt&lt;br /&gt;method$:L10840700&lt;br /&gt;  IF_ALWAYS CMPS lmmr10, lmmr1&lt;br /&gt;&lt;br /&gt;  long @method$:L10840700&lt;br /&gt;  IF_ALWAYS RDWORD PC, PC&lt;br /&gt;  IF_ALWAYS ADD lmmr10, #1&lt;br /&gt;  IF_ALWAYS MOV lmmr10, lmmr10&lt;br /&gt;method$:L11631043&lt;br /&gt;  IF_ALWAYS MOV lmmr0, lmmr10&lt;br /&gt;&lt;br /&gt;  long @method$:L10840700&lt;br /&gt;  IF_ALWAYS RDWORD PC, PC&lt;br /&gt;  IF_ALWAYS MOV lmmr0, #0&lt;br /&gt;method&lt;br /&gt;method$:L29315749&lt;br /&gt;  IF_ALWAYS MOV lmmr10, #1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;lmmr0&lt;/code&gt; and &lt;code&gt;lmmr1&lt;/code&gt; are the two function arguments (&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;this&lt;/code&gt;).  We smash &lt;code&gt;this&lt;/code&gt; almost immediately, reusing &lt;code&gt;lmmr0&lt;/code&gt; to hold &lt;code&gt;z&lt;/code&gt;, since it's the register used to return values from functions.&lt;br /&gt;&lt;br /&gt;One of these days it would be fun to take a class in this stuff, I think.  These are neat problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-6786615180415167591?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/6786615180415167591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=6786615180415167591' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6786615180415167591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6786615180415167591'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/12/linear-scan-register-allocator-adapted.html' title='Linear-scan register allocator adapted'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-8532433454328033067</id><published>2008-12-07T13:02:00.000-08:00</published><updated>2008-12-07T15:31:26.784-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='compilers'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='propeller'/><title type='text'>Adapting propasm for the Pilgrim LMM</title><content type='html'>Last night, I replaced my Java compiler's hacked code generator with one based around &lt;a href="http://code.google.com/p/propasm/"&gt;propasm&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Unfortunately, &lt;code&gt;propasm&lt;/code&gt; had some baked-in assumptions that gave me some trouble, so I had to rewrite it.  The rewrite will go into SVN as soon as it reaches feature-parity.  It's a lot simpler now and provides an API for extensible image generation -- which is the feature I needed today.&lt;br /&gt;&lt;br /&gt;You see, I'm targeting Phil Pilgrim's adaptation of the LMM, which is the only one with 16-cycle constant execution for register-register instructions.  (I developed it independently at Hobee's one night, but it looks like Phil did it first, so as far as I'm concerned it's the Pilgrim LMM.)&lt;br /&gt;&lt;br /&gt;The Pilgrim LMM has an unusual property that lets it achieve its speed: it lays code out &lt;em&gt;backwards&lt;/em&gt;, from high addresses to low, and uses &lt;code&gt;djnz&lt;/code&gt; to update the native and LMM PCs simultaneously.  This completely broke poor &lt;code&gt;propasm&lt;/code&gt;'s brain -- it was designed for single-pass assembly, which of course means that instructions get laid out in the order they're input.&lt;br /&gt;&lt;br /&gt;To support this, &lt;code&gt;propasm&lt;/code&gt; now generates images in two passes.  First, it builds a tree of object describing the image's contents.  Second, it walks the tree and generates output.  This has the side-effect of allowing optimizations on machine code without requiring a separate object model -- I've implemented a couple simple scalar optimizations over &lt;code&gt;propasm&lt;/code&gt;'s image objects in my compiler.&lt;br /&gt;&lt;br /&gt;My Java compiler plugs a class called &lt;code&gt;rlmm.CodeSegment&lt;/code&gt; into &lt;code&gt;propasm&lt;/code&gt;'s image generation code, which lets it generate the code in execution order (by a CFG walk) but lay it out backwards in memory.  Thus, for the sample input from my last post, we now get the following output:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;' Start of segment rlmm.CodeSegment@1004901&lt;br /&gt;  IF_ALWAYS JMPRET prim_return_ret, #prim_return&lt;br /&gt;method$:L10840700&lt;br /&gt;  IF_ALWAYS MOV r0, r2&lt;br /&gt;&lt;br /&gt;  long @method$:L10840700&lt;br /&gt;  long @method$:L15980197&lt;br /&gt;  IF_ALWAYS JMPRET prim_jmplt_ret, #prim_jmplt&lt;br /&gt;method$:L29181730&lt;br /&gt;  IF_ALWAYS CMPS r2, r1&lt;br /&gt;&lt;br /&gt;  long @method$:L29181730&lt;br /&gt;  IF_ALWAYS RDLONG PC, PC&lt;br /&gt;method$:L15980197&lt;br /&gt;  IF_ALWAYS ADDS r2, #1&lt;br /&gt;&lt;br /&gt;  long @method$:L29181730&lt;br /&gt;  IF_ALWAYS RDLONG PC, PC&lt;br /&gt;method$:L15006066&lt;br /&gt;method&lt;br /&gt;  IF_ALWAYS MOV r2, #0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Remember to read bottom-to-top!  (Pardon the excessive &lt;code&gt;IF_ALWAYS&lt;/code&gt; and expansion of &lt;code&gt;call&lt;/code&gt;s, this output was disassembled with a na&amp;iuml;ve algorithm.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-8532433454328033067?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/8532433454328033067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=8532433454328033067' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/8532433454328033067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/8532433454328033067'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/12/adapting-propasm-for-pilgrim-lmm.html' title='Adapting propasm for the Pilgrim LMM'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-5631074666620215952</id><published>2008-12-06T01:12:00.000-08:00</published><updated>2008-12-06T01:37:38.042-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='compilers'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='propeller'/><title type='text'>Compiling Java for the Propeller</title><content type='html'>My spare time is pretty limited these days -- work takes up a lot of it.  On the up-side, I got promoted.&lt;br /&gt;&lt;br /&gt;Over the past few months, some of my spare time has been spent designing a Java compiler that targets the Parallax Propeller.  A few hand-coded mockups have convinced me that it's feasible -- the only thing between that and making it a reality are the past 50 years of compiler research, which I never learned. :-)&lt;br /&gt;&lt;br /&gt;So, I've spent time surfing Citeseer and gathering data.  Between what I've learned and my Propeller experience, I've set some parameters for the first version: it will compile to Large Memory Model code rather than a custom interpreter, and will consume Java class files.&lt;br /&gt;&lt;br /&gt;As of this evening I've got a prototype working, and have compiled/assembled/uploaded my first binary.  The bullet points are as follows:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Converts Java 6 JVML to n-address linear IR using abstract evaluation.  Assumes input is verifiable, which lets me skip some checking.  (Why Java 6?  Because it generates nice frame attributes and doesn't use jsr.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Operates almost exclusively in SSA (actually CSSA).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Performs register allocation in SSA form, using a crippled-but-developing version of Pereira's algorithm.  I've modified it to deal more gracefully with the Propeller's CISC-like two-address architecture.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Provides limited scalar optimizations -- the ones I've gotten around to writing.  Copy folding, constant propagation, jump-to-flow-control elimination, etc.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Fantastically crappy code generator for now -- literally &lt;code&gt;printf&lt;/code&gt;-based with no intelligent layout or peephole optimizations, as you'll see in the samples below.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;None of the fun stuff, like garbage collection, works yet.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Here's sample input and output from one of my test suites&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Input0 {&lt;br /&gt;  public int function(int x) {&lt;br /&gt;   int y = 0;&lt;br /&gt;    while (y &lt; x) {&lt;br /&gt;      y ++;&lt;br /&gt;    }&lt;br /&gt;    return y;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the output, in propasm syntax (a superset of Parallax):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;method_function&lt;br /&gt;L12893404&lt;br /&gt;  mov r2, #0&lt;br /&gt;  rdlong PC, PC  ' inlined jmp&lt;br /&gt;  long @@L23063136&lt;br /&gt;L26210109&lt;br /&gt;  add r2, #1&lt;br /&gt;  rdlong PC, PC  ' inlined jmp&lt;br /&gt;  long @@L23063136&lt;br /&gt;L23063136&lt;br /&gt;  ' [int r2:1] &lt;- phi ssa.BasicBlock@c4bcdc:[int c0:0] ssa.BasicBlock@18fef3d:[int r2:2]&lt;br /&gt;  cmps r2, r1 wc wz&lt;br /&gt;  call #prim_lt&lt;br /&gt;  long @@L26210109&lt;br /&gt;  long @@L25763215&lt;br /&gt;L25763215&lt;br /&gt;  mov r0, r2&lt;br /&gt;  call #prim_return&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The "call #prim_foo" instructions are calls to LMM kernel traps; plenty of other people have explained Propeller LMM in detail elsewhere, I won't repeat it.  My code generator inlines LMM primitives in some cases, as it's done with jump here.&lt;br /&gt;&lt;br /&gt;Some details of the calling conventions are apparent in the output: incoming arguments start at r0, and the returned value comes back in r0.  These registers are real-live Propeller registers inside the LMM kernel, and I suspect I'll have room for a lot of them -- 32 or more -- so I'm using a RISC-like register calling convention, with link register.&lt;br /&gt;&lt;br /&gt;Assuming work doesn't interfere, I'll post more as it develops.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-5631074666620215952?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/5631074666620215952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=5631074666620215952' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5631074666620215952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5631074666620215952'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/12/compiling-java-for-propeller.html' title='Compiling Java for the Propeller'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-8200637707730652904</id><published>2008-11-27T13:10:00.000-08:00</published><updated>2008-11-27T13:13:44.257-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='acer aspire one'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Ubuntu 8.10 on the Acer Aspire One</title><content type='html'>I've replaced my eee 701 with an Acer Aspire One.  Ubuntu works quite well on it, without a lot of the trickery I needed on the eee, and the battery life is stunning (I get upwards of 7 hours after tweaks).&lt;br /&gt;&lt;br /&gt;I've created &lt;a href="http://sites.google.com/a/mg8.org/ubuntu-aa1/"&gt;a site with tutorials on getting Ubuntu working optimally on the Aspire One&lt;/a&gt;.  It includes &lt;a href="http://sites.google.com/a/mg8.org/ubuntu-aa1/step-by-step"&gt;a complete step-by-step guide for going from installation to awesome&lt;/a&gt;, based on the detailed notebook I kept in the first two days I had the machine.&lt;br /&gt;&lt;br /&gt;The machine, incidentally, is smaller than the notebook. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-8200637707730652904?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/8200637707730652904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=8200637707730652904' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/8200637707730652904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/8200637707730652904'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/11/ubuntu-810-on-acer-aspire-one.html' title='Ubuntu 8.10 on the Acer Aspire One'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-6871040299451485980</id><published>2008-11-24T12:09:00.001-08:00</published><updated>2008-11-24T12:11:08.853-08:00</updated><title type='text'>Amazon wrong; Acer Aspire One has no free mini-PCIe slot.</title><content type='html'>Amazon's product page for the &lt;a href="http://www.amazon.com/Acer-8-9-inch-Processor-Battery-Sapphire/dp/tech-data/B001EYV9TM/ref=de_a_smtd"&gt;Acer Aspire One&lt;/a&gt; claims that the machine has an available mini-PCIe slot for WWAN.&lt;br /&gt;&lt;br /&gt;I'm holding it in my hands, and it does not -- the connector isn't soldered in place, just like earlier ones.&lt;br /&gt;&lt;br /&gt;This is the first time Amazon's product descriptions have had a significant error in my experience, and I'm pretty pissed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-6871040299451485980?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/6871040299451485980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=6871040299451485980' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6871040299451485980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6871040299451485980'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/11/amazon-wrong-acer-aspire-one-has-no.html' title='Amazon wrong; Acer Aspire One has no free mini-PCIe slot.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-8338858251629091042</id><published>2008-05-26T23:19:00.000-07:00</published><updated>2008-05-26T23:24:38.597-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>PropellerForth issue tracker</title><content type='html'>I've gotten a few blog comments from folks who are using PropellerForth.  Yay!&lt;br /&gt;&lt;br /&gt;A few comments have reported bugs.&lt;br /&gt;&lt;br /&gt;I don't closely follow comments on my blog (though I respond when I have time) -- but I &lt;em&gt;do&lt;/em&gt; get a email when someone reports a bug at the &lt;a href="http://code.google.com/p/propellerforth/issues/list"&gt;PropellerForth issue tracker&lt;/a&gt; over on Google Code!&lt;br /&gt;&lt;br /&gt;If you're using PropellerForth and find a problem, please report it there.  (Please don't post "bugs" like "You haven't released a binary in a few months" or "You haven't imported your Subversion repo."  I assure you I'm working on both as time permits, but this isn't my day job.)&lt;br /&gt;&lt;br /&gt;Of course, if you're using PropellerForth and &lt;em&gt;haven't&lt;/em&gt; found a problem, I'd love to hear about that too!  Blog comments are a fine place for that, or send me an email if you can track down my address. ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-8338858251629091042?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/8338858251629091042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=8338858251629091042' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/8338858251629091042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/8338858251629091042'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/05/propellerforth-issue-tracker.html' title='PropellerForth issue tracker'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-7906137187773609002</id><published>2008-05-19T21:16:00.000-07:00</published><updated>2008-05-24T21:41:38.212-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>Trig in PropellerForth</title><content type='html'>Among many other nice features, the Parallax Propeller microcontroller has a single-quadrant sine table in ROM.  This makes implementing sine and cosine fast and simple, for medium-precision (13-bit) work.&lt;br /&gt;&lt;br /&gt;Here's a simple port of Parallax's routines to PropellerForth.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;hex&lt;br /&gt;&lt;br /&gt;\ Address of table in ROM&lt;br /&gt;E000 constant sin-base&lt;br /&gt;&lt;br /&gt;\ Computes the sign of an angle.&lt;br /&gt;\ The angle is a 13-bit number (0x1FFF = almost 360 degrees).&lt;br /&gt;\ The result is a 16.16 fixed-point signed integer.&lt;br /&gt;: sin  ( angle13 -- n16_16 )&lt;br /&gt;  dup 1000 and &gt;R   \ Stash a flag for Quadr.3/4 onto the rstack&lt;br /&gt;  dup 0800 and if  negate  then  \ Invert angle for Quadr.2/4&lt;br /&gt;  2* sin-base or  H@   \ Compute word address and fetch&lt;br /&gt;  R&gt; if  negate  then ;  \ Negate result for Quadr.3/4&lt;br /&gt;&lt;br /&gt;: cos  ( angle13 -- n16_16 )  0800 + sin ;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With PropellerForth v8.05 this gives a runtime of 1088-1152 cycles for &lt;code&gt;sin&lt;/code&gt;, and an additional 240 cycles for &lt;code&gt;cos&lt;/code&gt; -- 31x slower than a native implementation.  (v8.02 will be slower.)  &lt;br /&gt;&lt;br /&gt;It can be made slightly faster by (1) replacing the numbers with CONSTANTs and (2) inlining 2*, which is not a primitive, as "1 lshift", for a runtime of 993-1056 cycles -- 28x slower than native, at the cost of a 22 more bytes of space.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; Huh.  Through some optimizations to the kernel, I can shave off another 100 cycles -- for a runtime of  896-926 cycles.  However, it costs 248 bytes in the kernel, and eliminates a hook I was hoping to use for single-step and breakpoints.  I'll have to weigh this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-7906137187773609002?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/7906137187773609002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=7906137187773609002' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7906137187773609002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7906137187773609002'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/05/trig-in-propellerforth.html' title='Trig in PropellerForth'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-4374031124987826440</id><published>2008-05-17T00:23:00.000-07:00</published><updated>2008-05-17T02:11:22.366-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><category scheme='http://www.blogger.com/atom/ns#' term='pfcam'/><title type='text'>Another PFcam teaser</title><content type='html'>With the help of the new scope, I wrote a new OV6620 driver that includes chroma support.  With the camera reconfigured to run at 25fps, it records 88x72 YUV images at full rate.  It's 210 bytes, and integrated into a custom build of PropellerForth.&lt;br /&gt;&lt;br /&gt;A few lines of Forth later, I had code to generate PPM images.  (PPM is possibly the world's easiest format to produce.)  Here are some samples.  Forgive the yellow cast and the chroma noise -- my new workbench doesn't have lights yet, and the camera's low-lum performance is poor.  That, and I probably have bugs in my YUV matrix code.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/pfcam-chroma-test.png" width="176" height="144"/&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/pfcam-chroma-test2.png" width="176" height="144"/&gt;&lt;br /&gt;&lt;br /&gt;Once I'm confident in the design, I'll post the driver and Gerbers for the PCB (and if anyone actually wants one, we can go in on a BatchPCB order).&lt;br /&gt;&lt;br /&gt;I've got 8 spare Propeller I/O pins...gotta figure out what to do with 'em.  Servo connectors?  Debug LEDs?  Audio?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit:&lt;/strong&gt;  Yes, I did indeed have bugs in my matrix code!  They're fixed now.&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/pfcam-chroma-test3.png" width="176" height="144" /&gt;&lt;br /&gt;Better chroma makes engineer happy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4374031124987826440?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4374031124987826440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4374031124987826440' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4374031124987826440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4374031124987826440'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/05/another-pfcam-teaser.html' title='Another PFcam teaser'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-5580970312118641505</id><published>2008-05-13T22:00:00.000-07:00</published><updated>2008-05-13T22:17:55.575-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><category scheme='http://www.blogger.com/atom/ns#' term='pfcam'/><title type='text'>I can see clearly now, the waves are gone</title><content type='html'>I'm a pretty hardcore guy when it comes to debugging software.  I pride myself on my automated tests, I routinely sling debuggers and disassemblers around, and so forth.&lt;br /&gt;&lt;br /&gt;When it comes to hardware, though, I've been stuck firmly in the &lt;code&gt;printf&lt;/code&gt; era.  The &lt;code&gt;printf&lt;/code&gt; era is pretty damn powerful, of course, when you've got Forth at your side -- the PropellerForth VGA and NTSC display drivers, for example, were written using only a multimeter and ancient HeathKit frequency counter.&lt;br /&gt;&lt;br /&gt;However, I'm not a big fan of making my own life difficult.  After many years of fondling scopes at Fry's, I finally gave in and picked up a Tektronix TDS1012B.  It's at the high-end of the extreme low-end: decent sampling rates for embedded work and so forth.&lt;br /&gt;&lt;br /&gt;A couple weekends ago I taught myself printed circuit board and built the PFcam, the Propeller-based image processing board I mentioned in &lt;a href="http://cliffhacks.blogspot.com/2008/05/got-tired-of-my-cmucam.html"&gt;my last post&lt;/a&gt;.  I'm not an analog electronics whiz, so the first thing I did with my scope was test the new board.&lt;br /&gt;&lt;br /&gt;Sure enough -- here's a capture of some I2C traffic between the Propeller and the camera:&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/i2c-before.png" width="320" height="240"/&gt;&lt;br /&gt;&lt;br /&gt;Notice the square waves are wearing hats?  The regulator's output was bouncing between 3.3v (the goal) and 5v (the input).  A decoupling cap later, my SCCB code (Omnivision-speak for I2C) is much more reliable:&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/i2c-after.png" width="320" height="240"/&gt;&lt;br /&gt;&lt;br /&gt;Now all the I2C/SCCB chips play nice together, and nobody wigs out and sees a stop condition where there ain't one.&lt;br /&gt;&lt;br /&gt;I'm happy with the scope so far.  I'll most more details on the PFcam board later on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-5580970312118641505?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/5580970312118641505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=5580970312118641505' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5580970312118641505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5580970312118641505'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/05/i-can-see-clearly-now-waves-are-gone.html' title='I can see clearly now, the waves are gone'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-6663526395279817735</id><published>2008-05-07T22:37:00.000-07:00</published><updated>2008-05-08T21:44:39.886-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><category scheme='http://www.blogger.com/atom/ns#' term='pfcam'/><title type='text'>Got tired of my CMUcam.</title><content type='html'>What embedded machine vision system...&lt;ul&gt;&lt;br /&gt;&lt;li&gt;is easier to interface (and more powerful) than a CMUcam2;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;has eight cores at 96MHz, six of which can perform user-defined image processing;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;can be programmed and debugged interactively in-system using Forth or assembler;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;runs open-source code built using open-source tools;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;costs less than $100 in parts; and&lt;/li&gt;&lt;br /&gt;&lt;li&gt;can be built in an evening with only basic through-hole soldering?&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Yeah, I couldn't find one either.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/pfcam-front.jpg" width="320" height="240"/&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/pfcam-back.jpg" width="320" height="240"/&gt;&lt;br /&gt;&lt;br /&gt;Mmm, 192 MIPS of pixel-devouring goodness.  I love my overclocked Propellers.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit:&lt;/strong&gt; What kind of image processing, you ask?  How about realtime ASCII art!&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/images/pfcam-ascii-nntt.jpg" width="400" height="300"/&gt;&lt;br /&gt;&lt;br /&gt;I hope to get middle-mass and edge tracking working shortly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-6663526395279817735?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/6663526395279817735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=6663526395279817735' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6663526395279817735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6663526395279817735'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/05/got-tired-of-my-cmucam.html' title='Got tired of my CMUcam.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-4307331202348800515</id><published>2008-02-10T23:08:00.001-08:00</published><updated>2008-02-10T23:18:42.512-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>PropellerForth tidbit: running a word at boot time</title><content type='html'>By default, PropellerForth v8.01 starts up by running the built-in word &lt;code&gt;INTERACTIVE&lt;/code&gt;.  This displays the version screen, enables multitasking, and drops into the Forth interpreter by calling the standard word &lt;code&gt;QUIT&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Once you've built an application and burned it to EEPROM using &lt;code&gt;savemem&lt;/code&gt;, you may not want PropellerForth to be interactive anymore!  Alternatively, you might define a new version of &lt;code&gt;INTERACTIVE&lt;/code&gt; that does some additional setup -- SD card initialization, for example -- and then calls the old &lt;code&gt;INTERACTIVE&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I neglected to provide an easy way to run your own words on boot in v8.01, so here it is:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;decimal&lt;br /&gt;\ The address of a variable containing the first word to run.&lt;br /&gt;140 constant 'boot&lt;br /&gt;&lt;br /&gt;\ Sets a word to run at startup.&lt;br /&gt;\ Example: BOOT MYSTARTUP&lt;br /&gt;: boot ( "name" -- )&lt;br /&gt;  '  'boot ! ;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can simulate a reboot -- assuming you haven't started any other tasks -- by invoking an arcane Propeller machine instruction:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;32 0 coginit&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once you're satisfied, &lt;code&gt;savemem&lt;/code&gt; and &lt;code&gt;reboot&lt;/code&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4307331202348800515?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4307331202348800515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4307331202348800515' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4307331202348800515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4307331202348800515'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/02/propellerforth-tidbit-running-word-at.html' title='PropellerForth tidbit: running a word at boot time'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-6407358766702638529</id><published>2008-02-10T22:53:00.000-08:00</published><updated>2008-02-10T23:01:35.115-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>PropellerForth tidbit: changing the console speed</title><content type='html'>PropellerForth 8.01, by default, sets the console at 19,200 baud.&lt;br /&gt;&lt;br /&gt;This is mostly for compatibility, and doesn't tax the serial driver; in practice, the I/O routines spend most of their time sleeping.  At 80MHz the kernel I/O routines have no trouble doing 230kBps.  Increasing the speed can really make a difference when moving a bunch of data to the console, such as when dumping a block of RAM or listing a block of source.&lt;br /&gt;&lt;br /&gt;Currently the speed is hardcoded, but that doesn't mean we can't change it. :-)&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;\ Set the console I/O speed in bits per second.&lt;br /&gt;\ Takes effect immediately.&lt;br /&gt;\ Example:  115200 console-speed&lt;br /&gt;decimal&lt;br /&gt;: console-speed  ( u -- )&lt;br /&gt;  second swap /    \ get # of cycles per bit&lt;br /&gt;  176 L! ;         \ change the kernel's constant bit time&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The magic number there, 176, is the location of the bit time constant inside the kernel -- we use &lt;code&gt;L!&lt;/code&gt;, &lt;em&gt;local-store&lt;/em&gt;, to override it in the running kernel image.  176 is valid for 8.01 and early alphas of 8.02, but may change in the future -- eventually there will be a supported way of doing this.&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-6407358766702638529?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/6407358766702638529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=6407358766702638529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6407358766702638529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/6407358766702638529'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/02/propellerforth-tidbit-changing-console.html' title='PropellerForth tidbit: changing the console speed'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-7925197860673170380</id><published>2008-02-10T22:20:00.000-08:00</published><updated>2008-02-10T22:45:25.060-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Java 6 try/finally compilation without jsr/ret</title><content type='html'>My day job requires me to be a bit of a JVM geek, so I was poring over the Java Virtual Machine spec recently when I remembered something:  In Java 6 and later, the old &lt;code&gt;jsr&lt;/code&gt; and &lt;code&gt;ret&lt;/code&gt; instructions are effectively deprecated.  These instructions were used to build mini-subroutines inside methods.  While Java doesn't support nested functions or anything fun like that, it &lt;em&gt;does&lt;/em&gt; have the &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;finally&lt;/code&gt; construct, and these instructions were quite handy for implementing it.&lt;br /&gt;&lt;br /&gt;I saw no "official" instructions for compiling &lt;code&gt;finally&lt;/code&gt; without &lt;code&gt;jsr&lt;/code&gt;, so I investigated it, and thought I'd post the results -- mostly in case I forget them later.&lt;br /&gt;&lt;br /&gt;For non-Java folks, some background: a chunk of code that might fail at runtime can be wrapped in a &lt;code&gt;try&lt;/code&gt; block.  You can then attach handlers for specific types of exceptions/errors to the &lt;code&gt;try&lt;/code&gt; block using &lt;code&gt;catch&lt;/code&gt; clauses, if you want to respond to specific failure cases.  You can also attach a &lt;code&gt;finally&lt;/code&gt; block, which will be run at the end, &lt;em&gt;failure or no&lt;/em&gt;.  You can think of &lt;code&gt;finally&lt;/code&gt; as a sort of cleanup block -- which, in practice, is how it's used.&lt;br /&gt;&lt;br /&gt;As a result, you wind up with multiple control flow paths that can execute the &lt;code&gt;finally&lt;/code&gt; code:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;try block, successful completion, finally block executes before moving on&lt;/li&gt;&lt;br /&gt;&lt;li&gt;try block, failure, one or more catch blocks, finally block executes before moving on&lt;/li&gt;&lt;br /&gt;&lt;li&gt;try block, unhandled failure, finally block executes before unwinding the stack and throwing the error out to a higher level&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Java originally compiled this the way most folks would write it by hand: code that gets used multiple places goes in a subroutine.  In this case, it's a nested subroutine accessed using &lt;code&gt;jsr&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;This unfortunately makes dataflow analysis and type inference of the Java code considerably more complex, for reasons I won't go into here.&lt;br /&gt;&lt;br /&gt;So while Java 6 and later JVMs can still understand &lt;code&gt;jsr&lt;/code&gt;, tools no longer generate it.  Instead, they duplicate the code of the &lt;code&gt;finally&lt;/code&gt; block along each path (a transform I've always called &lt;em&gt;tail duplication&lt;/em&gt;, but there may be other names).    Let's look at a quick example.&lt;br /&gt;&lt;br /&gt;This totally contrived Java class plays with an array:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class TryFinally {&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    int[] a = new int[2];&lt;br /&gt;    try {&lt;br /&gt;      a[16] = 2;&lt;br /&gt;    } catch (ArrayIndexOutOfBoundsException e) {&lt;br /&gt;      a[0] = 2;&lt;br /&gt;    } finally {&lt;br /&gt;      a[1] = 2;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It will always follow the longest code path, because it's written to fail: the try block will execute, followed by the handler, followed by the finally clause.&lt;br /&gt;&lt;br /&gt;The disassembled JVM instructions for this method are as follows:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public static void main(java.lang.String[]);&lt;br /&gt;  Code:&lt;br /&gt;   0:   iconst_2       // Create the array&lt;br /&gt;   1:   newarray int&lt;br /&gt;   3:   astore_1       // Store it in local 1&lt;br /&gt;   4:   aload_1        // Set element 16 to 2 (throws)&lt;br /&gt;   5:   bipush  16&lt;br /&gt;   7:   iconst_2&lt;br /&gt;   8:   iastore&lt;br /&gt;   9:   aload_1        // Begin 'success' finally code&lt;br /&gt;   10:  iconst_1&lt;br /&gt;   11:  iconst_2&lt;br /&gt;   12:  iastore&lt;br /&gt;   13:  goto    35     // End 'success' finally code&lt;br /&gt;   16:  astore_2       // Catch block, save the exception...&lt;br /&gt;   17:  aload_1        // and set a[0] = 2&lt;br /&gt;   18:  iconst_0&lt;br /&gt;   19:  iconst_2&lt;br /&gt;   20:  iastore&lt;br /&gt;   21:  aload_1        // Catch copy of finally code&lt;br /&gt;   22:  iconst_1&lt;br /&gt;   23:  iconst_2&lt;br /&gt;   24:  iastore&lt;br /&gt;   25:  goto    35&lt;br /&gt;   28:  astore_3       // A third copy of finally code!&lt;br /&gt;   29:  aload_1&lt;br /&gt;   30:  iconst_1&lt;br /&gt;   31:  iconst_2&lt;br /&gt;   32:  iastore&lt;br /&gt;   33:  aload_3&lt;br /&gt;   34:  athrow&lt;br /&gt;   35:  return&lt;br /&gt;  Exception table:&lt;br /&gt;   from   to  target type&lt;br /&gt;     4     9    16   Class java/lang/ArrayIndexOutOfBoundsException&lt;br /&gt;     4     9    28   any&lt;br /&gt;    16    21    28   any&lt;br /&gt;    28    29    28   any&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see in my annotations, we have three copies of the finally code!  Why three?  The answer is in the three code paths I discussed above, and in the exception table.&lt;br /&gt;&lt;br /&gt;In the table we see four exception handlers defined -- but, of course, we only defined one!  Why so many?&lt;br /&gt;&lt;br /&gt;The first is the one we defined as a &lt;code&gt;catch&lt;/code&gt;.  The second is an invisible additional &lt;code&gt;catch&lt;/code&gt; on the &lt;code&gt;try&lt;/code&gt; block for type 'any' -- so any unexpected exceptions are sent to the third copy of the &lt;code&gt;finally&lt;/code&gt; code.  The third guards the catch block itself; the fourth guards the generated exception handler.&lt;br /&gt;&lt;br /&gt;In other words, the compiler has rewritten the Java code into something resembling:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    int[] a = new int[2];&lt;br /&gt;    try {&lt;br /&gt;      a[16] = 2;&lt;br /&gt;      a[1] = 2;&lt;br /&gt;    } catch (ArrayIndexOutOfBoundsException e) {&lt;br /&gt;      a[0] = 2;&lt;br /&gt;      a[1] = 2;&lt;br /&gt;    } catch (* e) {&lt;br /&gt;      a[1] = 2;&lt;br /&gt;      throw e;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;As you can see, the &lt;code&gt;finally&lt;/code&gt; block has disappeared -- instead, its contents have been duplicated along each code path.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-7925197860673170380?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/7925197860673170380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=7925197860673170380' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7925197860673170380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7925197860673170380'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/02/java-6-tryfinally-compilation-without.html' title='Java 6 try/finally compilation without jsr/ret'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-5952623256606895513</id><published>2008-02-07T20:14:00.000-08:00</published><updated>2008-02-07T23:36:21.795-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>New features for PropellerForth 8.02</title><content type='html'>I'm fleshing out the feature set for PropellerForth 8.02, due out in a couple weeks.  This is just a teaser post describing what I've been working on; no code yet. :-)&lt;br /&gt;&lt;br /&gt;The main new features at this time:&lt;ul&gt;&lt;li&gt;Block word set for reading/writing block devices and loading source code from storage&lt;/li&gt;&lt;li&gt;EEPROM Block backend, for treating the program EEPROM as a block device&lt;/li&gt;&lt;li&gt;SPI-mode SD/MMC card Block backend&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The SD support is a traditional Forth disk layer: it doesn't implement FAT or any other filesystem.  Instead, it lets you directly address blocks on the disk.  By default you can use this to save and edit source code directly on the card, but it could also allow an enterprising individual to implement filesystem support.&lt;br /&gt;&lt;br /&gt;Because source is stored in raw disk sectors instead of files, getting at it from a "real" computer will require a tool like &lt;code&gt;dd&lt;/code&gt;.  Since this is an embedded system, that doesn't bother me too much, but I wouldn't complain if someone implemented FAT16! :-)&lt;br /&gt;&lt;br /&gt;The actual interface code is a direct port of Tom Rokicki's FSRW SPIN implementation.  It's about 1KiB and currently gets about 5-6KiBps at 80MHz, twice the throughput of the SPIN version, despite being a pretty literal port.  I hope to optimize it further before release.&lt;br /&gt;&lt;br /&gt;Now, to work on a target compiler -- so that users of 8.02 can recompile their whole system from sources stored on EEPROM or SD.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-5952623256606895513?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/5952623256606895513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=5952623256606895513' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5952623256606895513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5952623256606895513'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/02/new-features-for-propellerforth-802.html' title='New features for PropellerForth 8.02'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-7607540307647270881</id><published>2008-01-20T22:47:00.001-08:00</published><updated>2008-01-20T22:50:38.141-08:00</updated><title type='text'>You keep using that word.</title><content type='html'>Poking around on the internet this evening, I ran across an ad for &lt;a href="http://www.microsoft.com/systemcenter/"&gt;a product intended to help manage "really, really big" server deployments&lt;/a&gt;.  I was intrigued, since that's what I do for a living, so I kept watching.&lt;br /&gt;&lt;br /&gt;Then this screen came up:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_QJ5DeVoa_UY/R5RAK9-ZWwI/AAAAAAAAAAM/v3mq8Frf254/s1600-h/Picture+1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_QJ5DeVoa_UY/R5RAK9-ZWwI/AAAAAAAAAAM/v3mq8Frf254/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5157818030425201410" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;*cough*  "Big."  You keep using that word.  I do not think it means what you think it means.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-7607540307647270881?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/7607540307647270881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=7607540307647270881' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7607540307647270881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7607540307647270881'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/01/you-keep-using-that-word.html' title='You keep using that word.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_QJ5DeVoa_UY/R5RAK9-ZWwI/AAAAAAAAAAM/v3mq8Frf254/s72-c/Picture+1.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-4300431671172936621</id><published>2008-01-01T13:18:00.000-08:00</published><updated>2008-01-01T13:50:10.739-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hydra'/><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>PropellerForth v8.01 alpha; HYDRA tidbit</title><content type='html'>After my winter sprint, PropellerForth v8.01 alpha has been posted on the &lt;a href="http://code.google.com/p/propellerforth/"&gt;project page&lt;/a&gt;.  (I'm using Ubuntu-style version numbers, so 8.01 is the January 2008 release.)&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/propellerforth/wiki/FrequentlyAskedQuestions"&gt;FAQ&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/propellerforth/wiki/ReleaseNotes0801"&gt;Release Notes&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/propellerforth/wiki/SupportedTargets"&gt;Supported target boards&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/propellerforth/wiki/GettingStarted"&gt;Getting Started guide&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;As it says in the release notes, the version currently available there is an &lt;em&gt;alpha&lt;/em&gt; release.  It's been tested, it works, and it's probably close to the final release, but I reserve the right to make changes in the near future before pronouncing it official.  In particular, the docs are not nearly complete -- I'm working on it.&lt;br /&gt;&lt;br /&gt;Source hasn't been posted yet; still trying to figure out how best to do that.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;A HYDRA PropellerForth Tip&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://parallax.com/Store/Microcontrollers/PropellerProgrammingKits/tabid/144/CategoryID/20/List/0/SortField/0/Level/a/ProductID/467/Default.aspx"&gt;HYDRA board&lt;/a&gt; is one of PropellerForth's officially supported targets.  One of its slick (but undocumented) features is how it handles the on-board EEPROM when a cartridge is inserted: it gets remapped to a higher address space, but remains accessible.&lt;br /&gt;&lt;br /&gt;PropellerForth's EEPROM words (included in the v8.01 'full' release) support addressing multiple EEPROMs on the I2C bus, using Atmel-style device and page addressing.  The visible address space is:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;No cartridge: onboard EEPROM at 0x00000 - 0x1FFFF&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Cartridge: onboard EEPROM at 0x20000 - 0x3FFFF, cartridge at 0x00000 - 0x1FFFF&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;This opens some interesting possibilities:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Programs could use both EEPROMs together, for 256KiB of bulk data storage.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;A reasonably simple Forth word could copy one EEPROM to the other, to clone a cartridge or back up the on-board software.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I'll leave those as exercises to the reader; for now, here's a word, &lt;code&gt;?cart&lt;/code&gt;, that checks whether a cartridge is currently inserted in the HYDRA.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;hex   \ the base of champions&lt;br /&gt;: ?cart  ( -- flag )&lt;br /&gt;  \ Try to read base of remapped on-board EEPROM.&lt;br /&gt;  20000 ['] eeread catch  \ Guard with catch to intercept failure&lt;br /&gt;  nip   \ Discard the address (if failed) or the result (if succeeded), leaving exception&lt;br /&gt;  0= ;  \ If the exception is 0 (none caught), return 'true', otherwise 'false'.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To help you test it, here is the cartridge monster.  (Hey, I can only type in so many dry source examples before I try to make one funny.)&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;: O_O  \ See, it's a face.  ... well, I thought it was funny. :-P&lt;br /&gt;  ?cart  if exit  then  \ Don't bug the user if a cartridge is present&lt;br /&gt;  begin  \ Loop and complain...&lt;br /&gt;    ." CARTRIDGE MONSTER WANT CARTRIDGE" cr&lt;br /&gt;    1 seconds wait&lt;br /&gt;  ?cart until  \ ... until a cartridge appears&lt;br /&gt;  ." NOM NOM NOM BURP" cr ;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(Hot-swapping cartridges on the HYDRA should work fine as long as the EEPROM is not being accessed when it happens -- just be careful to insert the cartridge straight.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4300431671172936621?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4300431671172936621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4300431671172936621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4300431671172936621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4300431671172936621'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2008/01/propellerforth-v801-alpha-hydra-tidbit.html' title='PropellerForth v8.01 alpha; HYDRA tidbit'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-5415092353452747180</id><published>2007-12-27T22:03:00.000-08:00</published><updated>2007-12-28T14:44:13.553-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>PropellerForth I2C EEPROM driver</title><content type='html'>This afternoon, I curled up with the datasheets for Atmel's I2C EEPROMs, like the one the Propeller uses to boot.  I haven't written any I2C code in a while, so I had to relearn the protocol.&lt;br /&gt;&lt;br /&gt;Then, I went out for ph&amp;#x1EDF;.  The place down the street is quite tolerant of me sitting for half an hour drawing state diagrams.&lt;br /&gt;&lt;br /&gt;Noodles completed, I set to work interfacing PropellerForth to the boot EEPROM.  It's been a resounding success.  The sources are below; they &lt;em&gt;should&lt;/em&gt; work on the old 20061124 image, if anyone still has a copy.  Otherwise, they'll work on the 20080101 image once I make it available.&lt;br /&gt;&lt;br /&gt;Executive summary: these words implement a hardcoded interface to an EEPROM on pins 29:28.  This lets you access data stored in EEPROM (using &lt;code&gt;ee@&lt;/code&gt; and &lt;code&gt;ee!&lt;/code&gt;).  For the first time, &lt;strong&gt;you can save a bootable image of your current PropellerForth system to EEPROM&lt;/strong&gt;, using the &lt;code&gt;saveforth&lt;/code&gt; word.&lt;br /&gt;&lt;br /&gt;The emphasis there shows how excited I am about this.  Bootstrapping my NTSC display driver requires me to carefully type in Forth code for several minutes, each time I reboot!  The words are factored so I can test as I go, but it's still painful.  This is about as revolutionary as when I got cassette storage working with my TRS-80 Model 100 and no longer had to type in BASIC listings.&lt;br /&gt;&lt;br /&gt;The interface is not spectacularly fast; page reads can stream data at about 20kbps, and page writes aren't implemented yet.  &lt;code&gt;saveforth&lt;/code&gt; can take a minute or two.  It is, however, pretty simple and readable, assuming you read Forth.&lt;br /&gt;&lt;br /&gt;If you don't read Forth, it's worth taking a glance at the code anyway.  It's not the best Forth code -- I'm rusty -- but casual observers may notice that code toward the top of the listing tends to be low-level (written in terms of machine registers like &lt;code&gt;OUTA&lt;/code&gt;).  As you progress through the listing, the language changes: first to a physical-level description of I2C, then to a layer-2 description of how to talk to the EEPROM.  In my day job we refer to this as a &lt;em&gt;domain-specific language&lt;/em&gt;.  Forth programmers didn't coin this term, because they didn't need one: it's the natural way to build systems in Forth.&lt;br /&gt;&lt;br /&gt;So: the code!  I've hand-escaped this, and may have introduced errors in the process.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; sneaky bug fixed by addition of &lt;code&gt;mkboot&lt;/code&gt; word.  Details below the source listing for anyone who doesn't want to figure it out for themselves. :-)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;hex  \ my dad will surely rib me for not using octal&lt;br /&gt;&lt;br /&gt;\ Sets the value of an output pin (identified by 'mask').&lt;br /&gt;\ Output is 0 if 'f' is false, 1 otherwise.&lt;br /&gt;: pin! ( f mask -- )&lt;br /&gt;  swap if&lt;br /&gt;    OUTA L@ or&lt;br /&gt;  else&lt;br /&gt;    OUTA L@ swap -and&lt;br /&gt;  then OUTA L! ;&lt;br /&gt;&lt;br /&gt;\ Sets a pin (identified by 'mask') to output.&lt;br /&gt;: pin&amp;gt; ( mask -- )&lt;br /&gt;  DIRA L@ or DIRA L! ;&lt;br /&gt;&lt;br /&gt;\ Sets a pin (identified by 'mask') to input.&lt;br /&gt;: &amp;lt;pin ( mask -- )&lt;br /&gt;  dira L@ -and dira L! ;&lt;br /&gt;&lt;br /&gt;\ I2C pin masks.  Workaround for CONSTANT bug (CONSTANTs are 16-bit).&lt;br /&gt;: eesdamask 20000000 ; \ pin 29&lt;br /&gt;: eesclmask 10000000 ; \ pin 28&lt;br /&gt;&lt;br /&gt;\ Words for working with the EEPROM SDA line.&lt;br /&gt;: eesda! ( f -- )  eesdamask pin! ;&lt;br /&gt;: eesda@ ( -- f )  INA L@  eesdamask and ;&lt;br /&gt;: eesda&amp;gt;  eesdamask pin&amp;gt; ;&lt;br /&gt;: &amp;lt;eesda  eesdamask &amp;lt;pin ;&lt;br /&gt;&lt;br /&gt;\ Words for working with the EEPROM SCL line.&lt;br /&gt;: eescl! ( f -- )  eesclmask pin! ;&lt;br /&gt;: eescl&amp;gt;  eesclmask pin&amp;gt; ;&lt;br /&gt;: &amp;lt;eescl  eesclmask &amp;lt;pin ;&lt;br /&gt;&lt;br /&gt;\ Initializes the bus; useful for resetting a b0rked chip&lt;br /&gt;: eeinit&lt;br /&gt;  \ SCL high/output, SDA input&lt;br /&gt;  1 eescl!  eescl&amp;gt;  &amp;lt;eesda&lt;br /&gt;&lt;br /&gt;  \ Drain the device until we get an ACK, or we try 9 times&lt;br /&gt;  9 0 do&lt;br /&gt;    0 eescl!  1 eescl!&lt;br /&gt;    eesda@  if  unloop exit  then&lt;br /&gt;  loop ;&lt;br /&gt;&lt;br /&gt;\ I2C start condition&lt;br /&gt;: eestart&lt;br /&gt;  1 eescl!  eescl&amp;gt;&lt;br /&gt;  1 eesda!  eesda&amp;gt;  0 eesda!&lt;br /&gt;  0 eescl! ;&lt;br /&gt;&lt;br /&gt;\ I2C stop condition&lt;br /&gt;: eestop&lt;br /&gt;  1 eescl!&lt;br /&gt;  1 eesda!&lt;br /&gt;  &amp;lt;eescl&lt;br /&gt;  &amp;lt;eesda ;&lt;br /&gt;&lt;br /&gt;: eerxbit ( -- bit )   1 eescl!  eesda@  0 eescl! ;&lt;br /&gt;&lt;br /&gt;\ Transmits a byte, MSB first.  Returns ack bit.&lt;br /&gt;: eetx ( byte -- ackbit )&lt;br /&gt;  8 0 do&lt;br /&gt;    dup 80 and  eesda!&lt;br /&gt;    1 lshift&lt;br /&gt;    1 eescl! 0 eescl!&lt;br /&gt;  loop drop&lt;br /&gt;  \ Read ack bit&lt;br /&gt;  &amp;lt;eesda eerxbit&lt;br /&gt;  0 eesda! eesda&amp;gt; ;&lt;br /&gt;&lt;br /&gt;\ Receives 8 bits, sending 'ackbit' in response&lt;br /&gt;: eerx ( ackbit -- byte )&lt;br /&gt;  &amp;lt;eesda&lt;br /&gt;  0 8 0 do&lt;br /&gt;    1 lshift&lt;br /&gt;    eerxbit if 1 or then&lt;br /&gt;  loop&lt;br /&gt;  swap eesda! eesda&amp;gt;&lt;br /&gt;  1 eescl!  0 eescl! ;&lt;br /&gt;&lt;br /&gt;\ Like eetx, but throws file error if not acked.&lt;br /&gt;: eetx? ( byte -- )&lt;br /&gt;  eetx  if -25 throw then ;&lt;br /&gt;&lt;br /&gt;\ Sends a two-byte big-endian address.&lt;br /&gt;: eetxaddr? ( addr -- )&lt;br /&gt;  dup  8 rshift  FF and  eetx?&lt;br /&gt;  FF and  eetx? ;&lt;br /&gt;&lt;br /&gt;\ Reads a byte out of EEPROM.  Throws on failure.&lt;br /&gt;\ If you're feeling cryptic you could rename this&lt;br /&gt;\ eec@.&lt;br /&gt;: eeread ( addr -- byte )&lt;br /&gt;  eestart  A0 eetx?  eetxaddr?&lt;br /&gt;  eestart  A1 eetx?  1 eerx&lt;br /&gt;  eestop ;&lt;br /&gt;&lt;br /&gt;\ Writes a byte to EEPROM.  Throws on failure.&lt;br /&gt;: eewrite ( byte addr -- )&lt;br /&gt;  eestart A0 eetx? eetxaddr? eetx? eestop ;&lt;br /&gt;&lt;br /&gt;\ Reads a little-endian 32-bit integer from EEPROM.&lt;br /&gt;\ Throws on failure.&lt;br /&gt;\ Eventually this should use page read.&lt;br /&gt;: ee@ ( addr -- x )&lt;br /&gt;  0 4 0 do&lt;br /&gt;    8 rshift&lt;br /&gt;    over eeread  18 ( hex ) lshift or&lt;br /&gt;    swap 1+ swap&lt;br /&gt;  loop nip ;&lt;br /&gt;&lt;br /&gt;\ Waits for the EEPROM to become available.  Required&lt;br /&gt;\ after a write operation unless you're damn sure you're&lt;br /&gt;\ going to be busy for a while.&lt;br /&gt;: eewait   begin  eestart A0 eetx eestop  0= until ;&lt;br /&gt;&lt;br /&gt;\ Writes a little-endian 32-bit integer into EEPROM.&lt;br /&gt;\ Throws on failure.&lt;br /&gt;: ee! ( x addr -- )&lt;br /&gt;  4 0 do&lt;br /&gt;    2dup eewrite&lt;br /&gt;    1+  swap 8 rshift  swap&lt;br /&gt;    eewait&lt;br /&gt;  loop 2drop ;&lt;br /&gt;&lt;br /&gt;\ Reads 'count' bytes from the EEPROM starting at 'addr'&lt;br /&gt;\ into a buffer at 'dest'.&lt;br /&gt;: eereadpage ( dest count addr -- )&lt;br /&gt;  over 0= if  drop drop drop exit  then&lt;br /&gt;  eestart A0 eetx? eetxaddr?&lt;br /&gt;  eestart A1 eetx?&lt;br /&gt;  ( count ) 1- 0 do&lt;br /&gt;    0 eerx over c!&lt;br /&gt;    1+&lt;br /&gt;  loop&lt;br /&gt;  1 eerx swap c!&lt;br /&gt;  eestop ;&lt;br /&gt;&lt;br /&gt;\ Updates fields in the image preamble to allow&lt;br /&gt;\ us to boot properly.&lt;br /&gt;: mkboot&lt;br /&gt;  here      08 H!&lt;br /&gt;  here 08 + 0A H!&lt;br /&gt;  here 0C + 0E H!&lt;br /&gt;  here 10 - 10 H! ;&lt;br /&gt;&lt;br /&gt;\ The word that made my evening: saves the&lt;br /&gt;\ current dictionary, kernel, and bootloader&lt;br /&gt;\ as a bootable image in EEPROM.  Takes a&lt;br /&gt;\ while, but prints cute little status updates.&lt;br /&gt;\ The resulting image will boot to the interpreter&lt;br /&gt;\ running the standard startup vector.&lt;br /&gt;\ &lt;br /&gt;\ CAVEAT HACKER: this will erase whatever's in&lt;br /&gt;\ EEPROM, in case that wasn't apparent.&lt;br /&gt;: saveforth&lt;br /&gt;  ." Saving 0 to "  here aligned . cr&lt;br /&gt;  mkboot&lt;br /&gt;  here aligned  0 do&lt;br /&gt;    i @ i ee!&lt;br /&gt;    i FF and 0= if&lt;br /&gt;      ." ..." i . cr&lt;br /&gt;    then&lt;br /&gt;  4 +loop&lt;br /&gt;  ." Done." ;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update about &lt;code&gt;mkboot&lt;/code&gt;:&lt;/strong&gt; the original listing I posted contained a subtle bug.  When booting the saved EEPROM image, 12 bytes in the middle of your first user-added colon definition were destroyed.  I didn't notice this because my first def was some test word that I didn't use after boot.&lt;br /&gt;&lt;br /&gt;As described in my &lt;a href="http://www.cliff.biffle.org/software/propeller/binary-format.html"&gt;article on reverse-engineering the Propeller's image format&lt;/a&gt;, the SPIN interpreter needs some RAM to start.  My image preamble (as used in propasm, and by extension PropellerForth) uses 12 bytes of RAM for the initial SPIN stack before the machine code is loaded.&lt;br /&gt;&lt;br /&gt;The preamble tells SPIN where to put its stack; propasm indicates that it should go right after the end of the code.  But if you've added code at runtime and saved Forth, the preamble needs to be updated -- otherwise SPIN will clobber an area just past the end of the original image, which is probably in the middle of a definition.&lt;br /&gt;&lt;br /&gt;So, &lt;code&gt;mkboot&lt;/code&gt; updates the preamble.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-5415092353452747180?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/5415092353452747180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=5415092353452747180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5415092353452747180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5415092353452747180'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/12/propellerforth-i2c-eeprom-driver.html' title='PropellerForth I2C EEPROM driver'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-4180624085802462927</id><published>2007-12-27T00:00:00.001-08:00</published><updated>2007-12-27T10:55:21.435-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ntsc'/><category scheme='http://www.blogger.com/atom/ns#' term='propellerforth'/><title type='text'>PropellerForth stirrings</title><content type='html'>A few weeks ago, I was poking around on the Silicon Valley Forth Interest Group webpage.  I was surprised to see this in their minutes:&lt;br /&gt;&lt;blockquote&gt;There has been no success in contacting the author of Propeller Forth - written locally by Cliff L. Biffle&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;As of about February 2007, my email got so clogged with spam that I simply stopped checking it.  (Apologies to anyone who's been trying to contact me.)  So, I had no idea that the SVFIG was interested in PropellerForth.  I've had isolated inquiries from a couple people, but all in all, my original posts (here and on the Parallax forums) were met with general disinterest.&lt;br /&gt;&lt;br /&gt;So, I've resurrected the project.  Not much progress yet -- mostly, I'm cleaning up the sources so I can release them without sullying my good name. :-)  People poking around the &lt;a href="http://code.google.com/p/propellerforth/"&gt;PropellerForth site on code.google.com&lt;/a&gt; might notice some documentation appearing in preparation for the source release.&lt;br /&gt;&lt;br /&gt;Ever since I moved out of my folks' house, I've gone back and spent a few nights there for Christmas.  Since my sleep schedule is rather different from theirs, I wind up having a lot of free time -- and since I'm away from work and distraction, it's traditionally been a great opportunity to hack.  (Projects that got their start or reached significant milestones over Christmas include Mongoose, Cesta, PropellerForth -- and, 15 years earlier, WebElite.)&lt;br /&gt;&lt;br /&gt;This year I learned the NTSC spec, the US analog television standard.  The existing NTSC drivers for the Propeller are cryptic and don't build with propasm, so I wrote a very simple one with more lines of comment than code.  It generates a 40x16 B&amp;W text display, uses the ROM font to save space (compressing it on the fly to 8x16 pixels), and requires 336 bytes of code space and 640 bytes of framebuffer.  As an experiment, I've tied it into PropellerForth.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/ntsc-emit.jpg" width="500" height="375" /&gt;&lt;br /&gt;&lt;br /&gt;It probably won't be part of the base image I release -- it bloats the image beyond my 8KiB target -- but between it and my PS/2 driver from Christmas 2006, I've nearly got a standalone console working.&lt;br /&gt;&lt;br /&gt;(NTSC, incidentally, is a pain compared to VGA -- but most of the complexity, as my dad pointed out, is a result of sending all the data amplitude-modulated on a single channel, instead of VGA's five.  It's kind of impressive that they got this to work in the 30s.)&lt;br /&gt;&lt;br /&gt;So, if anyone following my blog is interested in PropellerForth, let this at least indicate that your interest may not be in vain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4180624085802462927?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4180624085802462927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4180624085802462927' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4180624085802462927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4180624085802462927'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/12/propellerforth-stirrings.html' title='PropellerForth stirrings'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-1498730137236323843</id><published>2007-11-27T11:19:00.000-08:00</published><updated>2007-11-30T16:44:09.755-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='eee'/><title type='text'>ASUS eeePC: some sources posted.</title><content type='html'>Looks like ASUS has posted some source archives on &lt;a href="ftp://ftp.asus.com/pub/ASUS/EeePC/"&gt;their FTP site&lt;/a&gt;.  On initial inspection, the asus_acpi module sources are &lt;em&gt;not&lt;/em&gt; the ones that compiled the module that ships on the machine, but are very close.  Gonna try 'em out this evening -- as long as they work, I can chalk the previous binary release up to an error on ASUS's part and forge ahead.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit (2007-11-30):&lt;/strong&gt; I've pored over ASUS's source release and extracted their changes into patches.  Everything seems to work -- they even released some packages that they weren't technically obligated to, like their on-screen display code for the volume and wifi buttons.&lt;br /&gt;&lt;br /&gt;I'm delighted to report that this situation is resolved, as far as I'm concerned.  ASUS has reacted admirably and swiftly, and I'm proud to have given them my money (with the small exception of the arbitrary and potentially illegal restrictions they've placed on upgrades).&lt;br /&gt;&lt;br /&gt;Gonna go back to my enjoying my laptop now, and hopefully not get viciously attacked on Slashdot and my own blog for a while.  Happy hacking!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-1498730137236323843?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/1498730137236323843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=1498730137236323843' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/1498730137236323843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/1498730137236323843'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/11/asus-eeepc-some-sources-posted.html' title='ASUS eeePC: some sources posted.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-2243013195338996531</id><published>2007-11-25T10:16:00.001-08:00</published><updated>2007-11-25T10:31:00.585-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='eee'/><title type='text'>eeebuntu tip: unloading/reloading the wifi drivers</title><content type='html'>The eee's wifi does not survive a suspend: the hardware and drivers get into different states, and things quit working.  The wifi control scripts in ASUS's Linux distribution hold the key.&lt;br /&gt;&lt;br /&gt;There's a particular sequence of rmmod/insmod calls that will force the system to rediscover the wifi, and (for me at least) fixes all the various b0rked states it can get into.  I call it the "Magic Wifi Dance," because it's a ritual that I don't completely understand.&lt;br /&gt;&lt;br /&gt;My control script is below.  You'll need the Atheros drivers and the ASUS ACPI module.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;# The sequence here *may* be important.&lt;br /&gt;# (It seems to fail intermittently if you deviate.)&lt;br /&gt;unload_modules() {&lt;br /&gt;   rmmod wlan_scan_sta&lt;br /&gt;   rmmod wlan_tkip&lt;br /&gt;   rmmod wlan_wep&lt;br /&gt;   rmmod wlan_ccmp&lt;br /&gt;   rmmod wlan_acl&lt;br /&gt;   rmmod ath_pci&lt;br /&gt;   sleep 1&lt;br /&gt;   rmmod ath_rate_atheros&lt;br /&gt;   rmmod ath_hal&lt;br /&gt;   rmmod wlan&lt;br /&gt;   rmmod ath_dfs&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# At least this one's straightforward.&lt;br /&gt;load_modules() {&lt;br /&gt;   modprobe ath_pci&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;wifi_on() {&lt;br /&gt;   # Force PCI Express Hotplug to reinit&lt;br /&gt;   rmmod pciehp&lt;br /&gt;   sleep 1&lt;br /&gt;   # pciehp_force may be unnecessary; Xandros did it.&lt;br /&gt;   modprobe pciehp pciehp_force=1&lt;br /&gt;   sleep 1&lt;br /&gt;   # Switch on the hardware&lt;br /&gt;   echo 1 &gt;/proc/acpi/asus/wlan&lt;br /&gt;   sleep 1&lt;br /&gt;   load_modules&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;wifi_off() {&lt;br /&gt;   unload_modules&lt;br /&gt;   echo 0 &gt;/proc/acpi/asus/wlan&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;case $1 in&lt;br /&gt;   on)&lt;br /&gt;      wifi_on&lt;br /&gt;      ;;&lt;br /&gt;   off)&lt;br /&gt;      wifi_off&lt;br /&gt;      ;;&lt;br /&gt;   toggle)&lt;br /&gt;      STAT=`cat /proc/acpi/asus/wlan`&lt;br /&gt;      if [ "$STAT" = "1" ];&lt;br /&gt;         then wifi_off;&lt;br /&gt;         else wifi_on;&lt;br /&gt;      fi&lt;br /&gt;      ;;&lt;br /&gt;esac&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When executed on an "eeebuntu" machine with ASUS's binary modules, that script should be capable of shutting down and bringing up the Atheros wifi card.  The &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt; arguments do what their names imply; the &lt;code&gt;toggle&lt;/code&gt; argument checks the card's status in proc and responds appropriately.  (I use &lt;code&gt;toggle&lt;/code&gt; to make the keyboard's wifi key work, which I'll demonstrate in my upcoming post on ACPI events.)&lt;br /&gt;&lt;br /&gt;For those playing along at home, this resulting control script is a good one to call from &lt;code&gt;/etc/acpi/suspend.d&lt;/code&gt; and &lt;code&gt;/etc/acpi/resume.d&lt;/code&gt;, with &lt;code&gt;off&lt;/code&gt; and &lt;code&gt;on&lt;/code&gt; arguments, respectively.  (Just make sure it's called after the interfaces are shut down on suspend, and before they're brought up on resume.  On default Ubuntu, calling the suspend script "56-eee-wifi-off" and the resume script "60-eee-wifi-on" gets the order right.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-2243013195338996531?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/2243013195338996531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=2243013195338996531' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/2243013195338996531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/2243013195338996531'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/11/eeebuntu-tip-unloadingreloading-wifi.html' title='eeebuntu tip: unloading/reloading the wifi drivers'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-7425858922518733260</id><published>2007-11-24T23:39:00.000-08:00</published><updated>2007-11-24T23:50:17.918-08:00</updated><title type='text'>eeebuntu tip: ifup/down for NetworkManager</title><content type='html'>By switching to NetworkManager, I lost the use of the Linux &lt;code&gt;ifup&lt;/code&gt;/&lt;code&gt;ifdown&lt;/code&gt; scripts for quickly bringing network interfaces up and down.  (These scripts rely on the information in &lt;code&gt;/etc/network/interfaces&lt;/code&gt;, which I've stripped bare to transfer control to NetworkManager.)&lt;br /&gt;&lt;br /&gt;Now, with &lt;code&gt;nm-applet&lt;/code&gt; and kin, I have no real need or desire to control my network interfaces from the shell.  However, some of my other scripts do -- in particular, when suspending and resuming the machine, I need to remove/reload the Atheros kernel modules, and I can't do that while the interface is up.&lt;br /&gt;&lt;br /&gt;Also, my keyboard has a cute little "Wifi On/Off" button that I want to work.  (More info on that in a later post.)&lt;br /&gt;&lt;br /&gt;Fortunately, the solution turns out to be dead-simple: NetworkManager's dbus API exposes methods for bringing the network up and down.&lt;br /&gt;&lt;br /&gt;To bring all NetworkManager-controlled interfaces down:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;dbus-send --system --type=method_call \&lt;br /&gt;  --dest=org.freedesktop.NetworkManager \&lt;br /&gt;  /org/freedesktop/NetworkManager \&lt;br /&gt;  org.freedesktop.NetworkManager.sleep&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;(Yes, all those switches are necessary.)&lt;br /&gt;&lt;br /&gt;To bring 'em back up:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;dbus-send --system --type=method_call \&lt;br /&gt;  --dest=org.freedesktop.NetworkManager \&lt;br /&gt;  /org/freedesktop/NetworkManager \&lt;br /&gt;  org.freedesktop.NetworkManager.wake&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In my case, I dropped these into scripts in &lt;code&gt;/etc/acpi/suspend.d&lt;/code&gt; and &lt;code&gt;/etc/acpi/resume.d&lt;/code&gt;, respectively, alongside their old-school ifup/down counterparts.  Works great, assuming the drivers come back up; I'll post the trick for that in a subsequent post.  (I'm transcribing my porting notes as fast as I can here.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-7425858922518733260?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/7425858922518733260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=7425858922518733260' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7425858922518733260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7425858922518733260'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/11/eeebuntu-tip-ifupdown-for.html' title='eeebuntu tip: ifup/down for NetworkManager'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-1849409755239477319</id><published>2007-11-24T22:58:00.000-08:00</published><updated>2007-11-24T23:39:21.415-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='eee'/><title type='text'>eeebuntu tip: wireless with hal and NetworkManager</title><content type='html'>I've been away from Linux for quite a while, off in Mac-land, where things generally just work.  I was delighted to notice, upon my return, that the community (and RedHat in particular) noticed that manually configuring your wireless interfaces is lame, and built a solution: NetworkManager.&lt;br /&gt;&lt;br /&gt;NetworkManager is built atop hal, a daemon that interrogates hardware and makes the information available over a dbus interface.  (dbus is a simple mechanism for interprocess messaging and procedure call, similar to DCOP, but more general.)&lt;br /&gt;&lt;br /&gt;If you install Ubuntu and subsequently bring up your network using a panel applet, you're using NetworkManager -- and boy, is it nice.  Unfortunately, most instructions for getting the eee's wireless working on Ubuntu revolve around the "old-world" configuration mechanism in &lt;code&gt;/etc/network/interfaces&lt;/code&gt;.  While Ubuntu has graphical configurators that generate this file, using it prevents you from applying the full power of NetworkManager.  (Fun fact: NetworkManager will silently ignore any interfaces that are configured in &lt;code&gt;/etc/network/interfaces&lt;/code&gt;.)&lt;br /&gt;&lt;br /&gt;NetworkManager and hal are really poorly documented.  (No offense to the authors intended; the tech is impressive, and I understand that sometimes precious little time is left over to write a design document.)  I don't understand the system well enough to write a general tutorial, so here's a specific one: how to get NetworkManager and hal playing nice with the binary Atheros drivers on "eeebuntu" -- Ubuntu 7.10 using the ASUS-compatible 2.6.21.4 kernel I described in my last post.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Getting hal to create ath0 automatically&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;The Atheros wireless drivers create two network interfaces: &lt;code&gt;wlan0&lt;/code&gt; by default, which seems to be good for very little, and &lt;code&gt;ath0&lt;/code&gt; on demand, which is what you actually use to speak to the intarweb.  You have to explicitly request creation of the &lt;code&gt;ath0&lt;/code&gt; interface like so:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;wlanconfig ath0 create wlandev wlan0 wlanmode sta&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;hal, by default, sees the wlan0 interface as an 802.e interface, and does not see ath0 at all.  What we want is for hal to ignore wlan0 and treat ath0 as an 802.11 interface.  hal supports policy files (written in XML, which surprised me in a Linux tool) that rewrite its view of devices -- and that's what we'll use to fix this.&lt;br /&gt;&lt;br /&gt;But first -- we need ath0 created automatically when wlan0 appears.  A simple script suffices.  I've put mine in a file called &lt;code&gt;/etc/hal/callouts/eee-wifi&lt;/code&gt; for reasons that will become apparent in the next step.  The script need only contain:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;case $HALD_ACTION in&lt;br /&gt;  add)&lt;br /&gt;    sleep 1  # May be unnecessary, experiment&lt;br /&gt;    /sbin/wlanconfig ath0 create wlandev wlan0 wlanmode sta&lt;br /&gt;    sleep 1&lt;br /&gt;    ;;&lt;br /&gt;  remove)&lt;br /&gt;    /sbin/wlanconfig ath0 destroy&lt;br /&gt;    ;;&lt;br /&gt;esac&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that the script takes its input, not from a command-line parameter, but from an environment variable named &lt;code&gt;HALD_ACTION&lt;/code&gt;.  This will make sense in a minute.  For now, you can test the script thusly:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# Should create ath0 if wlan0 exists and drivers are loaded&lt;br /&gt;env HALD_ACTION=add /etc/hal/callouts/eee-wifi&lt;br /&gt;# Should remove ath0&lt;br /&gt;env HALD_ACTION=remove /etc/hal/callouts/eee-wifi&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, we convince hal to invoke our script when wlan0 appears or disappears.  Create a file named &lt;code&gt;/etc/hal/fdi/policy/10-networking-ath0.fdi&lt;/code&gt; containing the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="ISO-8859-1"?&amp;gt;&lt;br /&gt;&amp;lt;deviceinfo version="0.2"&amp;gt;&lt;br /&gt; &amp;lt;device&amp;gt;&lt;br /&gt;  &amp;lt;match key="net.interface" string="wlan0"&amp;gt;&lt;br /&gt;   &amp;lt;append key="info.callouts.add" type="strlist"&amp;gt;/etc/hal/callouts/eee-wifi&amp;lt;/append&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt; &amp;lt;/device&amp;gt;&lt;br /&gt;&amp;lt;/deviceinfo&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This adds our script as a  "callout" for wlan0 -- hal's notion of an event handler.  hal will invoke our script when wlan0 comes or goes, and set HALD_ACTION appropriately.&lt;br /&gt;&lt;br /&gt;Restart hal (or &lt;code&gt;killall -HUP hald&lt;/code&gt;) and try loading or unloading the Atheros drivers.  ath0 should be created and destroyed automatically.  (Make sure the ath0 interface is down when you do this.)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Letting NetworkManager configure ath0&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;For NetworkManager to configure an interface, a few conditions must be met:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;hal must see the interface and recognize it correctly (e.g. seeing ath0 as a wired Ethernet connection is not good);&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The interface &lt;em&gt;must not&lt;/em&gt; be configured in &lt;code&gt;/etc/network/interfaces&lt;/code&gt;.  If you currently have a stanza configuring ath0 or wlan0, remove it.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;First things first.  Modify the &lt;code&gt;10-networking-ath0.fdi&lt;/code&gt; policy we created in the last step by adding the code marked below:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="ISO-8859-1"?&amp;gt;&lt;br /&gt;&amp;lt;deviceinfo version="0.2"&amp;gt;&lt;br /&gt; &amp;lt;device&amp;gt;&lt;br /&gt;  &amp;lt;match key="net.interface" string="wlan0"&amp;gt;&lt;br /&gt;   &amp;lt;append key="info.callouts.add" type="strlist"&amp;gt;/etc/hal/callouts/eee-wifi&amp;lt;/append&amp;gt;&lt;br /&gt;   &lt;b&gt;&amp;lt;merge key="info.capabilities" type="strlist"&amp;gt;net&amp;lt;/merge&amp;gt;&lt;br /&gt;   &amp;lt;append key="info.capabilities" type="strlist"&amp;gt;net.80211&amp;lt;/append&amp;gt;&lt;br /&gt;   &amp;lt;merge key="info.category" type="string"&amp;gt;net.80211&amp;lt;/merge&amp;gt;&lt;br /&gt;   &amp;lt;merge key="net.interface" type="string"&amp;gt;ath0&amp;lt;/merge&amp;gt;&lt;br /&gt;   &amp;lt;merge key="net.80211.mac_address" type="copy_property"&amp;gt;net.80203.mac_address&amp;lt;/merge&amp;gt;&lt;br /&gt;   &amp;lt;remove key="net.80203.mac_address"&amp;gt;&amp;lt;/remove&amp;gt;&lt;br /&gt;   &amp;lt;merge key="linux.sysfs_path" type="string"&amp;gt;/sys/class/net/ath0&amp;lt;/merge&amp;gt;&lt;/b&gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt; &amp;lt;/device&amp;gt;&lt;br /&gt;&amp;lt;/deviceinfo&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Note:&lt;/strong&gt; special thanks to "Triarm" on the &lt;a href="forum.eeeuser.com"&gt;eeeuser forums&lt;/a&gt; for pointing out this approach.&lt;br /&gt;&lt;br /&gt;Line by line, this does the following:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Replaces wlan0's &lt;code&gt;info.capabilities&lt;/code&gt; property with the single item "net", indicating that it's a network interface.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Appends "net.80211", indicating that it's a wireless interface.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Changes the device's category, again to indicate that it's a wireless interface.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Switches the entry to refer to ath0, instead of wlan0.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Copies the 802.3 (wired Ethernet) MAC address to the 802.11 MAC address (I'm surprised that these are separate).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Removes the old 802.3 MAC address.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rewrites the entry's sysfs path to point to ath0's.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;To sum up, at this point we have:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Instructed hal to invoke our callout when wlan0 is added or removed, thereby automagically creating/destroying ath0.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rewritten the device descriptor for wlan0 to describe ath0 (which is unfortunately not picked up automatically by hal).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Removed wlan0/ath0 configuration from &lt;code&gt;/etc/network/interfaces&lt;/code&gt;.  (You remembered that, right?)&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Bring NetworkManager down, restart or HUP hald, and bring NetworkManager back up.  (The control script for NetworkManager on Ubuntu 7.10 is at &lt;code&gt;/etc/dbus-1/event.d/25NetworkManager&lt;/code&gt;.)&lt;br /&gt;&lt;br /&gt;Assuming I haven't forgotten anything, NetworkManager should now offer to configure your wireless, and the interface should show up in configurators like &lt;code&gt;nm-applet&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;If it doesn't work, try rebooting.  (I know it's lame to say that, but the Atheros drivers are incredibly sensitive and can get into weird states that make your interface stop working, usually after you remove/readd them or suspend/resume.  I have a magic dance that repairs the driver, but it's lengthy so I'll post it in a followup.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-1849409755239477319?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/1849409755239477319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=1849409755239477319' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/1849409755239477319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/1849409755239477319'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/11/eeebuntu-tip-wireless-with-hal-and.html' title='eeebuntu tip: wireless with hal and NetworkManager'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-5293374470571360433</id><published>2007-11-23T11:16:00.000-08:00</published><updated>2007-11-23T12:35:01.658-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='eee'/><title type='text'>eeebuntu tip: using a custom kernel with ASUS's modules</title><content type='html'>I like the eee hardware but dislike the software.  Personal preference; when I can't use a Mac I use Ubuntu.  Readers will surely like some other distro (I know I used to be big on Gentoo), but this tip should not be distro-specific.&lt;br /&gt;&lt;br /&gt;I wanted to put Ubuntu 7.10 on my eee without sacrificing any features.  I've largely pulled it off, but it's a long journey down a narrow, undocumented road (sigh, Linux).  The journey starts with the proverbial single step, which in this case is replacing the kernel with a largely identical one built from source.  (If you're going to do anything cool to the kernel, you've got to be able to build it.)&lt;br /&gt;&lt;br /&gt;I started out by installing Ubuntu 7.10 off a live stick.  This isn't strictly necessary -- the kernel we're building will probably work in Xandros -- but since Ubuntu is my eventual goal, I aimed high.  The live stick boots without a hitch (into Compiz, no less!) and the install was uneventful.  &lt;strong&gt;Note before installing:&lt;/strong&gt; there are files on the eee's filesystem you will need to complete this tutorial!  It is worth your time to make a backup in an accessible form, such as dd'ing the filesystem to somewhere you can loop-mount it.&lt;br /&gt;&lt;br /&gt;(Caveat lector: I actually installed onto an SD card, leaving the internal flash disk unmodified, but doing this requires a bunch of extra steps that &lt;em&gt;are not documented here&lt;/em&gt;.  It's sufficiently involved that I'll have to describe it in a followup.)&lt;br /&gt;&lt;br /&gt;The install was largely uneventful and is not the topic of this post.&lt;br /&gt;&lt;br /&gt;Ubuntu 7.10 does not, out of the box, support the following hardware on the eee:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The Atheros wireless card.  (The madwifi drivers ASUS ships are not the 9.3.3 drivers, and a freshly built set from SVN trunk doesn't work either.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The ASUS ACPI features for controlling backlight and powering PCIe devices on and off.  The mechanism is conceptually similar to the kernel's asus_acpi module, but as I noted in a previous post, ASUS ships a modified driver.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;(Those of you who have been in the Linux/FreeBSD laptop community for some time may notice how incredibly short that list is, and the fact that it &lt;em&gt;does not&lt;/em&gt; include multihead 3D accelerated graphics, audio, and USB 2.  How far we've come.)&lt;br /&gt;&lt;br /&gt;As a result of the botched ACPI support, suspend/resume doesn't work quite right.  Suspend-to-RAM will work sometimes, kinda, after a few VT switches to thunk the display adapter.  Not good enough!  I want instant suspend/resume and working wireless!  Waaaah, the Mac has spoiled me! :-)&lt;br /&gt;&lt;br /&gt;The pragmatic solution, if not the most FSF-friendly one, is to build a kernel with the exact version string from ASUS's so their binary modules will work.  (If you care, note your kernel will be tainted!  Danger Will Robinson!)&lt;br /&gt;&lt;br /&gt;The recipe below skips some steps and is not intended for Linux or Unix newbies.  Sorry; I've been immersed in Unix long enough that I'm not the right guy to write the newbie tutorial.  Feel free to steal my instructions to make one!&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Prereq: a Linux machine with a working set of devtools and the 2.6 version of depmod.  This might be the eee, I suppose, but I used a much faster machine.  (Specifically, an Ubuntu 7.10 virtual machine under VMware Fusion.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Download the sources for the matching Linux kernel version -- in this case, 2.6.21.4.  (For the kernel-impaired, it comes from &lt;a href="http://www.kernel.org/pub/linux/kernel/v2.6/"&gt;kernel.org's 2.6 site&lt;/a&gt;.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Untar.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Nab the ASUS kernel configuration, helpfully shipped right on your eee.  It lives in &lt;code&gt;/boot/config-2.6.21.4-eeepc&lt;/code&gt;.  Copy it into your untarred kernel sources as a file named &lt;code&gt;.config&lt;/code&gt; .&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If you tried to build the kernel now, you'd notice some errors about missing unionfs.  Unionfs isn't in the 2.6.21.4 mainline kernel, but ASUS uses it.  If you want it, &lt;a href="http://www.fsl.cs.sunysb.edu/project-unionfs.html"&gt;download the version for 2.6.21.7&lt;/a&gt; and apply it in the kernel tree with &lt;pre&gt;&lt;code&gt;patch -p1 &amp;lt;/path/to/patch&lt;/code&gt;&lt;/pre&gt;  If you don't want it, simply delete or comment out all lines in the config containing the word UNIONFS.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ASUS's config in place, build a replacement kernel by issuing &lt;pre&gt;&lt;code&gt;make oldconfig &amp;&amp; make&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Create a directory to hold your new kernel and modules, and issue &lt;pre&gt;&lt;code&gt;make INSTALL_PATH=/your/directory install&lt;br /&gt;make INSTALL_MOD_PATH=/your/directory modules_install&lt;/code&gt;&lt;/pre&gt;  You do not need to (and should not!) run these commands as root.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In your directory are a bunch of files: a kernel and associated files at the root, and a &lt;code&gt;lib/modules/2.6.21.4-eeepc&lt;/code&gt; directory with your modules in it.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Copy the files out of the directory into /boot on your eeepc.  Note at this point that, if you are still running Xandros, you have just overwritten your kernel.  Hope you had a backup.  (If you're running Ubuntu 7.10 you have installed an additional kernel alongside the main one.  This is safe.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Copy the contents of the &lt;code&gt;/lib...&lt;/code&gt; directory, &lt;em&gt;not into /boot with the others&lt;/em&gt;, but into &lt;code&gt;/lib/modules/2.6.21.4-eeepc&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Try booting your eee.  You will need to get to the grub menu and change the "kernel=" parameter.  (How to do this is beyond the scope of this article.)  If it does not work, I'm afraid I am not the man to help you; I make Linux work through sheer dumb luck and a lot of Unix engineering experience, but a Linux guru I'm not.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If it seems to work, simply copy the &lt;code&gt;atheros&lt;/code&gt; and &lt;code&gt;acpi&lt;/code&gt;. directories from &lt;code&gt;/lib/modules/2.6.21.4-eeepc&lt;/code&gt; on your eee backup filesystem into the same locations on the new one, and run (as root) &lt;code&gt;depmod -a&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;At this point, if it worked, you have a booting Ubuntu (or ${YOUR_DISTRO}) system running on a reasonable facsimile of ASUS's 2.6.21.4 kernel.  If you issue &lt;code&gt;modprobe asus_acpi&lt;/code&gt; or &lt;code&gt;modprobe ath_pci&lt;/code&gt;, the modules should load (and put some control files in /proc/acpi/asus, or create wlan0, respectively).&lt;br /&gt;&lt;br /&gt;You may find that suspend/resume to RAM works with the asus_acpi module loaded.  Edit your /etc/modules as you see fit.&lt;br /&gt;&lt;br /&gt;Getting from "loading the Atheros modules" to "reading Slashdot" is unfortunately involved -- but the process is no different than the normal madwifi drivers.  (Hint: until I post my scripts, search on Google for "wlanconfig ath0 create".)&lt;br /&gt;&lt;br /&gt;Happy hacking!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-5293374470571360433?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/5293374470571360433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=5293374470571360433' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5293374470571360433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5293374470571360433'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/11/eeebuntu-tip-using-custom-kernel-with.html' title='eeebuntu tip: using a custom kernel with ASUS&apos;s modules'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-1899622058944889508</id><published>2007-11-22T10:49:00.000-08:00</published><updated>2007-11-30T16:18:50.838-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gpl'/><category scheme='http://www.blogger.com/atom/ns#' term='eee'/><category scheme='http://www.blogger.com/atom/ns#' term='warrantyvoid'/><title type='text'>ASUS eeePC: First impressions and GPL violations</title><content type='html'>&lt;strong&gt;Most recent edit (2007-11-30):&lt;/strong&gt; please see my &lt;a href="http://cliffhacks.blogspot.com/2007/11/asus-eeepc-some-sources-posted.html"&gt;more recent post&lt;/a&gt; for updates.  ASUS has released the sources for some of the applications and drivers on the eee.  I can't say whether it's complete and accurate yet, but it's a great sign from ASUS.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit:&lt;/strong&gt; This post has gotten wider circulation than I was expecting (I rarely get readers, much less comments!).  I've been clarifying some points in the comments, but people don't seem to be reading them before posting (and some of the posts have been hostile in tone).  So:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Yes, I've downloaded and poked around in the 1.8GB archive ASUS insists is the source, from both the US and Taiwan sites.  It does not contain the sources in question, or at least did not when I retrieved it.  I tend to assume incompetence before malice, and I really do believe they just messed up.  (Even the asus_acpi stripping seems more like a botched search-replace job by some overworked driver author than a malicious act.  Doesn't make it legit, of course.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I realize that blogging about a GPL violation doesn't fix it.  My purpose in writing this article was to document the violation; I have neither the inclination nor the time to press a complaint or (god forbid) file a lawsuit!  If others want to do that in response to this post, I'm happy to serve as an expert witness and provide the evidence I've collected, but for now, I'm enjoying my laptop and a cup of coffee.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I either suck at using ndiswrapper (I freely admit this) or it's my Airport base station causing the problems there.  More on wireless drivers in a followup post.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Now on to the original post:&lt;br /&gt;&lt;br /&gt;For my birthday, I bought myself an &lt;a href="http://en.wikipedia.org/wiki/ASUS_Eee_PC"&gt;ASUS eeePC&lt;/a&gt;.  Now, I've been lusting after very-small-form-factor laptops for some time (ever since I saw the Zaurus C series), and this is quite the small one.  It also ships with Linux, which (I thought) was a good indication that the hardware is well supported by Linux.  (Not so; read on.)&lt;br /&gt;&lt;br /&gt;I'm very pleased with the hardware with a few exceptions, which I'll detail in the latter two thirds of this post.  The screen is bright and clear, the keyboard is surprisingly usable (even with my giant hands), etc.  I'm really happy with it, now that I've bent it to my will.  Obligatory laptop porn below.&lt;br /&gt;&lt;br /&gt;The eee on a sheet of 8.5x11 paper:&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/eee-on-paper.jpg" width="400" height="327"/&gt;&lt;br /&gt;&lt;br /&gt;The eee next to a coffee mug:&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/eee-with-mug.jpg" width="400" height="274"/&gt;&lt;br /&gt;&lt;br /&gt;The eee atop my 15" MacBook Pro:&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/eee-on-mac.jpg" width="400" height="373"/&gt;&lt;br /&gt;&lt;br /&gt;Now then.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Proprietary Hardware Woes&lt;/h2&gt;&lt;br /&gt;ASUS ships the eee with a variant of Xandros Linux, which in turn is a variant of Debian.  It also ships with binary modules for much of the hardware, and some of the hardware won't work without 'em.  Specifically,&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The wireless works with the madwifi version that ships on the machine, but not with HEAD or 9.3.3, and&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The ACPI does not work with the Linux kernel's asus_acpi module, but does with ASUS's variant of it.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Several folks have gotten the wifi working with ndiswrapper, but this just tells me that those folks don't run WEP.  (I need to figure out where they live.)  I've gotten both wifi and ACPI working in Ubuntu, but only by loading ASUS's binary modules.  Instructions in a subsequent post, once I'm done ranting.&lt;br /&gt;&lt;br /&gt;(&lt;strong&gt;Edit (2007-11-23):&lt;/strong&gt; Folks have posted saying they got ndiswrapper working with WPA.  They're clearly 1337er than I am; turning on any encryption at all would spike it to 50%+ CPU.  Lame!)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Proprietary Software Woes&lt;/h2&gt;&lt;br /&gt;The system is set to update itself and add packages from a repository at ASUS's site (specifically &lt;a href="http://update.eeepc.asus.com/p701/pool/"&gt;this one&lt;/a&gt;), where the little machine can fetch new kernels, Linux userland, KDE updates, and optional packages.&lt;br /&gt;&lt;br /&gt;What you won't find on that site are sources.  ASUS is bound by the GPL to make the sources for the software they're distributing available, even if they have not modified them.  (Check the license if you don't believe me.)  ASUS has posted a 1.8GB ZIP file on their website that they &lt;em&gt;claim&lt;/em&gt; is the sources, but it's not -- it contains a few .debs (not even the versions that ship on the machine) and some kernel headers.  (Perhaps they figured nobody would pull 1.8GB from their slow-as-molasses site and find out.)&lt;br /&gt;&lt;br /&gt;Through disassembly (I can do that, the software is GPL'd), it appears that ASUS has extensively modified the asus_acpi kernel module from Linux 2.6.21.4, so that it now works with the eee's hardware.  This would be good except that&lt;ul&gt;&lt;br /&gt;&lt;li&gt;They appear to have stripped out all attribution.  (Kernel modules contain information about the module name, version, and author.  This has been removed.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;They appear to have attempted to hide what they were doing.  (All references to "asus_acpi" have been removed, but other identifying features remain.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;They are not distributing their modified sources, or even a patch.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I have not contacted the author of asus_acpi, and it's possible that he has worked out a copyright licensing deal with ASUS -- but I was under the impression that the copyright of contributions to the Linux kernel were assigned to Linus or an agent thereof, which would not leave him with this right.&lt;br /&gt;&lt;br /&gt;The madwifi drivers that ship on the machine are also a version never before seen in the wild, but as madwifi is dual-licensed GPL/BSD, modifying it is within ASUS's rights.&lt;br /&gt;&lt;br /&gt;It's worth noting, from a legal perspective, that ASUS is also distributing BusyBox inside the system's initramfs image.  (They do not appear, at first glance, to have stripped the attribution out of this one.)  This is interesting because someone else distributing BusyBox without complying with the GPL is &lt;a href="http://www.softwarefreedom.org/news/2007/nov/20/busybox/"&gt;currently getting themselves sued&lt;/a&gt; in the first US civil suit over GPL violations.&lt;br /&gt;&lt;br /&gt;Also worth noting: this is not the first time that ASUS has stolen from the community in this way.  They were &lt;a href="http://gpl-violations.org/news/20040325-iptables.html"&gt;caught in 2004 stealing code from iptables/netfilter&lt;/a&gt;.  They're also &lt;em&gt;trying&lt;/em&gt; to cover their ass: they include the GPL in the box with the product, and state&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;This product includes copyrighted third-party software licensed under the terms of the GNU General Public License. ... ASUSTeK COMPUTER Inc. has exposed the full source code of the GPL licensed software, including any scripts to control compilation and installation the object code ... For more information how you can obtain our open source code, visit our website (http://support.asus.com.tw/download/).&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;...that website, for reference, is Home of the Giant Zip File I mentioned above.&lt;br /&gt;&lt;br /&gt;Sigh.&lt;br /&gt;&lt;br /&gt;(&lt;strong&gt;Edit (2007-11-23):&lt;/strong&gt; To be fair, as commenters have pointed out, this may very well be simple negligence on ASUS's part.  Yes, I and others have contacted ASUS about this with no response yet.  Let's hope they just say "Whoops!" and fix the ZIP.)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Warranty Void If Removed&lt;/h2&gt;&lt;br /&gt;The last annoyance about the eee PC is the bright yellow "Warranty void if seal is broken or removed" sticker over the RAM upgrade slot.&lt;br /&gt;&lt;br /&gt;Yes, you read that right: a computer manufacturer has decided that it voids your warranty to replace a DIMM.&lt;br /&gt;&lt;br /&gt;The door in question also hides an available mini-PCI-Express slot, so needless to say, people would like to open it.  For me, until I get out of the front of the bathtub curve and verify that the hardware works with Ubuntu, that sticker stays intact.&lt;br /&gt;&lt;br /&gt;However, since I'm already pretending to be a lawyer in this post, allow me to discuss the Magnuson-Moss Act, what it says about tie-ins, and what exactly ASUS is doing here.&lt;br /&gt;&lt;br /&gt;The Magnuson-Moss Act is a 1975 Federal law that lays down some rules for how consumer warranties work.  One of the specific things it prohibits are "tie-ins," additional items or services you must buy from the manufacturer to make your warranty work.  (This is why for-pay warranties these days are euphemistically termed 'service contracts.')&lt;br /&gt;&lt;br /&gt;Examples of tie-ins are &lt;a href="http://www.ftc.gov/bcp/conline/pubs/buspubs/warranty.shtm#Magnuson-Moss"&gt;provided on the FTC's site&lt;/a&gt;.  There's the unacceptable tie-in:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;In order to keep your new Plenum Brand Vacuum Cleaner warranty in effect, you must use genuine Plenum Brand Filter Bags. Failure to have scheduled maintenance performed, at your expense, by the Great American Maintenance Company, Inc., voids this warranty.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;...and the acceptable one:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;While necessary maintenance or repairs on your AudioMundo Stereo System can be performed by any company, we recommend that you use only authorized AudioMundo dealers. Improper or incorrectly performed maintenance or repair voids this warranty.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Specifically, it's acceptable to void someone's warranty if maintenance is &lt;em&gt;screwed up&lt;/em&gt;.  (I'm paraphrasing the FTC's page, which was clearly paid by the word.)&lt;br /&gt;&lt;br /&gt;Here are snippets from ASUS's warranty:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;The warranty only covers failures or malfunctions occurred during the warranty period and in normal use conditions as will as for any material or workmanship defect.  The warranty will not apply if: (a) the product has been tampered, &lt;em&gt;repaired, or modified by non-authorized personnel;&lt;/em&gt; ... &lt;em&gt;(c) the warranty seals have been broken or altered;&lt;/em&gt; ...&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;(Yes, those typos were in the original.)&lt;br /&gt;&lt;br /&gt;Clause (a) above is clearly unenforceable under Magnuson-Moss -- it's one of the specific cases that the FTC cites as illegal.&lt;br /&gt;&lt;br /&gt;Clause (c) follows as unenforceable: repairs (even normal upgrades) of the system &lt;em&gt;cannot be performed&lt;/em&gt; without breaking the warranty seal.  I'm not a lawyer, but I trust the judgment of judges; I doubt that a warranty stating "You can get this repaired by any qualified person but they can't look at it!" would be upheld.  This is no different.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit (2007-11-23):&lt;/strong&gt; One more note on my tie-in point: ASUS will be selling a "higher model" of the eee in the US, with more RAM and 8GB of Flash, starting at the end of this month.  Someone will open this model up and post pictures.  If the model is simply the original with a different DIMM and, say, a PCIe SSD dropped in, then what ASUS is saying is "These socketed, consumer-upgradeable parts will void your warranty if you touch them -- but if you pay &lt;em&gt;us&lt;/em&gt; another $150 we'll change them for you."  That's a bit more blatant than what I'd cited above.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-1899622058944889508?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/1899622058944889508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=1899622058944889508' title='159 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/1899622058944889508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/1899622058944889508'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/11/asus-eeepc-first-impressions-and-gpl.html' title='ASUS eeePC: First impressions and GPL violations'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>159</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-2678668524882643197</id><published>2007-03-31T14:58:00.000-07:00</published><updated>2007-04-01T21:19:04.116-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cesta'/><category scheme='http://www.blogger.com/atom/ns#' term='mongoose'/><category scheme='http://www.blogger.com/atom/ns#' term='llvm'/><title type='text'>Experimenting with LLVM</title><content type='html'>My oldest live projects are Mongoose and Cesta, both in intermittent development since 2003.  I'm doing a bit of hacking on both right now.&lt;br /&gt;&lt;br /&gt;In the case of Mongoose, writing my own VM (or, thus far, four of them) was fun, but it's not viable in the long term.  I'd like to target the language to an existing VM, but earlier attempts with the JVM and CLR bore little fruit.  (Neither VM is well-suited to dynamic languages with serious metaprogramming facilities.)&lt;br /&gt;&lt;br /&gt;In the case of Cesta, I need a way to speedily evaluate filter expressions, and a way to "cross-breed" decoders for parallel fuzzy decoding.&lt;br /&gt;&lt;br /&gt;Research on both topics kept leading me back to &lt;a href="http://llvm.org/"&gt;LLVM&lt;/a&gt;, which is many things:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;It's a compiler, with frontends for C, C++, and several other languages;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It's a library for designing and implementing transformations on code;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It's a framework for building the backends of new compilers;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It's a well-defined low-level virtual machine;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It's an embeddable code generator, suitable for use in Just-In-Time compilers.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Initially, I was scared of LLVM.  I did some hacking on the GCC family of compilers a few years ago, and the code is abjectly terrifying &amp;mdash; not to mention the deliberately obfuscated intermediate representations.  However, &lt;em&gt;every&lt;/em&gt; research lead I followed kept pointing back to LLVM.  Eventually, I got up the gumption to download it and try it out.&lt;br /&gt;&lt;br /&gt;In short: I am floored.  LLVM is almost absurdly easy to work with, thanks to the best-designed C++ API I've ever seen outside of Qt.  Within minutes of downloading it, I had built and tested some of my C code using &lt;code&gt;llvm-gcc&lt;/code&gt;, their drop-in replacement for GCC.&lt;br /&gt;&lt;br /&gt;An hour, two source examples, and 120 lines of code later, I had written a program that generates a Fibonacci function in RAM, JITs it to native x86, and executes it in process, printing the results.  (It might have taken longer if the LLVM guys hadn't provided an example that does exactly that, which I was able to learn from.)&lt;br /&gt;&lt;br /&gt;This is when I started to notice something: the JIT is impressively fast, considering that I had not activated any of LLVM's impressive suite of optimizations.  I coded up two version of the Fibonacci sequence (na&amp;iuml;ve and hand-optimized) and ran some benchmarks.&lt;br /&gt;&lt;br /&gt;The first is the na&amp;iuml;ve recursive version:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;int fibonacci(int x) {&lt;br /&gt;  if(x &lt;= 2) return 1;&lt;br /&gt;  return fib(x - 1) + fib(x - 2);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Compiled in a test harness, the times are as follows (suitably averaged and scrubbed of outliers):&lt;br /&gt;&lt;strong&gt;fib(24)&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O0&lt;/strong&gt;: 1136us&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O3&lt;/strong&gt;: 397us&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;LLVM JIT&lt;/strong&gt;: 771us&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;strong&gt;fib(40)&lt;/strong&gt; (note that units are now milliseconds)&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O0&lt;/strong&gt;: 1866ms&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O3&lt;/strong&gt;: 618ms&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;LLVM JIT&lt;/strong&gt;: 1578ms&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Generating this recursive Fibonacci function at runtime (which takes some milliseconds at startup, not included in this benchmark) produces code that runs &lt;em&gt;faster&lt;/em&gt; than GCC at -O0.  Neat.&lt;br /&gt;&lt;br /&gt;Next, the iterative transform of the function:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;int iterative_fibonacci(int x) {&lt;br /&gt;  if(x &lt;= 2) return 1;&lt;br /&gt;  int a = 1, b = 1, c;&lt;br /&gt;  while(x &gt; 2) {&lt;br /&gt;    c = a + b;&lt;br /&gt;    b = a;&lt;br /&gt;    a = c;&lt;br /&gt;    x--;&lt;br /&gt;  }&lt;br /&gt;  return c;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(The code to generate this at runtime is substantially more complex, since I'm assembling the SSA intermediate representation by hand in C++.)&lt;br /&gt;&lt;br /&gt;This algorithm is vastly faster than the previous version, so note that our units below are now &lt;em&gt;nanoseconds&lt;/em&gt;.&lt;br /&gt;&lt;strong&gt;fib(24)&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O0&lt;/strong&gt;: 170 ns&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O3&lt;/strong&gt;: 30 ns&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;LLVM JIT&lt;/strong&gt;: 51 ns&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;strong&gt;fib(40)&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O0&lt;/strong&gt;: 299 ns&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;GCC 4.0.1, -O3&lt;/strong&gt;: 51 ns&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;LLVM JIT&lt;/strong&gt;: 93 ns&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;On this version, LLVM shows an impressive performance gain over GCC at -O0, and is within a factor of 2 of GCC's output at -O3.  (&lt;strong&gt;Edit:&lt;/strong&gt; As noted in the comments, running GCC at -O0 is effectively tying both of its hands behind its back.  I understand this; I'm comparing to -O0 here because I've not aggressively optimized my LLVM code here and I &lt;em&gt;wanted&lt;/em&gt; to try a non-JIT compiler with its optimizations turned off.  It's still faster than the M3VM threaded interpreter.)&lt;br /&gt;&lt;br /&gt;To try this for yourself, here's where to find the sources:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The LLVM na&amp;iuml;ve Fibonacci code is in the LLVM distribution at &lt;code&gt;examples/Fibonacci&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.cliff.biffle.org/software/llvm/ifibonacci.cpp"&gt;The iterative LLVM Fibonacci code.&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.cliff.biffle.org/software/llvm/fib.c"&gt;The recursive C Fibonacci code (for GCC).&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.cliff.biffle.org/software/llvm/ifib.c"&gt;The iterative C Fibonacci code (for GCC).&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-2678668524882643197?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/2678668524882643197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=2678668524882643197' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/2678668524882643197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/2678668524882643197'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/03/experimenting-with-llvm.html' title='Experimenting with LLVM'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-7985063669821904969</id><published>2007-03-18T15:38:00.000-07:00</published><updated>2007-03-21T20:47:46.522-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>Cocoa Bindings: more on NSArrayController</title><content type='html'>After my post on NSArrayController's performance yesterday, Scott rightly pointed out that the behavior I was seeing might be a result of how I was using the class, rather than the class's implementation.&lt;br /&gt;&lt;br /&gt;I've boiled down the scenario into a bare-minimum project: &lt;a href="http://www.cliff.biffle.org/software/ArrayGrowDemo.zip"&gt;ArrayGrowDemo.zip&lt;/a&gt; (47k)&lt;br /&gt;&lt;br /&gt;I've kept the use of Bindings to the textbook case, illustrated below:&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/ArrayGrowDemo-bindings.png" width="307" height="296"/&gt;&lt;br /&gt;&lt;br /&gt;All in all, the only unusual thing I'm doing in the code (a slightly simplified version of the Cesta algorithm) is populating the array continuously from a backing thread, but coalescing the KVO notifications in a foreground thread.  For what it's worth, I see the same overall pattern by populating from a &lt;code&gt;perform&lt;/code&gt; from the main run loop -- the trends just show faster when the population isn't throttled by the performance of the UI.&lt;br /&gt;&lt;br /&gt;The application, when run, will write stats in CSV format to &lt;code&gt;/tmp/arraygrow.log&lt;/code&gt;.  Run it from Xcode, because you'll need that Terminate button handy: the UI becomes totally nonresponsive very quickly.  (This replicates the freeze I saw in the Cesta UI when processing a loaded gigabit link, when I was using NSArrayController.)&lt;br /&gt;&lt;br /&gt;Here's a graph from one of my test runs, leaving the NSTableView unsorted.  The blue line is the amount of time required to distribute KVO notification that the property has changed size (i.e. that the "array" has grown); from Shark profiles, this is where the NSArrayController code tends to slow down.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/nsarraycontroller-didchange.png" style="border:0px; padding: 0px; margin-left: -23px;" width="486" height="384"/&gt;&lt;br /&gt;&lt;br /&gt;(More specifically, the blue line is the time spent in &lt;code&gt;didChange:valuesAtIndexes:forKey:&lt;/code&gt; per invocation.  Its &lt;code&gt;willChange:&lt;/code&gt; brother appears to be constant-time.  The red line is the time spent in &lt;code&gt;didChange:&lt;/code&gt; divided by the number of items actually changed, showing that &amp;mdash; fortunately &amp;mdash; the NSArrayController isn't linear with regard to the number of &lt;em&gt;changed&lt;/em&gt; items...in Tiger....)&lt;br /&gt;&lt;br /&gt;I've run a few variations on this, which you can try by editing the Nib.  If you change the model key of either table column to "value.value.value.value", you can see the results of binding to a (pathologically) deeply nested property.  This appears to slow things down very slightly, and boosts the time spent in the KVO register/unregister code.  (I included this because I expected it to slow things down significantly; it doesn't.)&lt;br /&gt;&lt;br /&gt;When sorting the table view on either column, each update remains effectively O(n), but the actual time taken increases substantially.  (The sort operation, presumably O(n log n), is lost in the O(n) noise.)&lt;br /&gt;&lt;br /&gt;Oh kind readers, please take a look at this source and let me know what I'm doing wrong.  I would love to switch back to NSArrayController for my packet view in Cesta -- it would reduce the lines of code I have to maintain.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Updated the images to fit better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-7985063669821904969?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/7985063669821904969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=7985063669821904969' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7985063669821904969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7985063669821904969'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/03/cocoa-bindings-more-on.html' title='Cocoa Bindings: more on NSArrayController'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-5062387916680904509</id><published>2007-03-17T17:25:00.000-07:00</published><updated>2007-03-18T00:40:26.587-07:00</updated><title type='text'>Cocoa Bindings: mmm, crow</title><content type='html'>I should have learned this long ago: when I make a glowing blog post about something, I'm about to learn far more about it than I ever wanted to.&lt;br /&gt;&lt;br /&gt;I've been collecting Shark profiles of Cesta all day, as my own personal performance-fixit.  I've learned two things.&lt;br /&gt;1. My new decode logic is much faster than I anticipated.  (Good!)&lt;br /&gt;2. As a result, all of the CPU Cesta's been chewing up has been -- yes, Cocoa Bindings.&lt;br /&gt;&lt;br /&gt;The Bindings framework is not to blame.  It's the built-in Controller objects (&lt;strong&gt;Edit:&lt;/strong&gt; or, as Scott points out in the comments, the way I'm using them).  Specifically, NSArrayController seems to very aggressively make copies of the multi-valued property it controls.  I haven't decompiled it for specifics, but I see enormous NSArrays being allocated -- and that's a class that I specifically avoid.  (Granted, NSArrayController was probably not designed to be stuffed with thousands of rows per second.  Copying the array makes sense for smaller datasets.)&lt;br /&gt;&lt;br /&gt;Moreover, for some reason, it keeps invoking &lt;code&gt;indexOfObject:&lt;/code&gt;, which is almost by definition O(n/2) for an unsorted array.  When my captures start getting large (hundreds of thousands of packets), &lt;code&gt;indexOfObject:&lt;/code&gt; and its partner in crime, &lt;code&gt;CFEquals&lt;/code&gt;, start creeping up in my profiles.&lt;br /&gt;&lt;br /&gt;This is, of course, nonsense.  I've been very careful to only append objects to the end of my capture -- it's a time-series data recording, after all.  Unless I'm running a "Find" operation, there should be no reason to run around comparing things.&lt;br /&gt;&lt;br /&gt;After lunch today I started running into some really odd bugs with NSTreeController, where it appears to be allocating internal NSArrays to keep track of children, and then &lt;em&gt;reading right off the end of them&lt;/em&gt;.  I know I'm handling my retains and KVO correctly, so this seems to be a flaw in NSTreeController.&lt;br /&gt;&lt;br /&gt;So, I've stripped out all the NS*Controller objects.  More trouble than they're worth for this application.  I've replaced them with lightweight custom implementations that don't call &lt;code&gt;indexOfObject:&lt;/code&gt; or crash.  I now have an NSTableDataSource and NSOutlineDataSource again -- but they're both very thin, because I had already designed the data model to be presented in tables and trees.&lt;br /&gt;&lt;br /&gt;In subsequent profiling, I noticed something odd.  Removing NSArrayController and unbinding my packet table resulted in a 400% overall speedup, which I was expecting, but I got another boost in speed from removing NSTreeController, which I was not.  It seems to create an NSArrayController-like object behind the scenes, with all its attendant overhead.  (Not to mention that both NS*Controllers create callstacks of 40 or so frames, greatly boosting the use of objc_msgSend.)&lt;br /&gt;&lt;br /&gt;Thus, my previous post (which read something to the effect of "OMG BINDINGS ARE FAST") has not proven entirely accurate.  I would now rephrase that as follows:&lt;br /&gt;1. Bindings, themselves, are fast.  I'm still using them extensively to keep my controllers and data sources in sync.&lt;br /&gt;2. NSControllers, the typical use of Bindings, don't seem to scale well to large update frequencies.&lt;br /&gt;&lt;br /&gt;(&lt;strong&gt;Edit:&lt;/strong&gt; After discovering someone actually reading this blog, I cleaned up a couple cases of language that may have been overly pointed.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-5062387916680904509?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/5062387916680904509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=5062387916680904509' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5062387916680904509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/5062387916680904509'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/03/cocoa-bindings-mmm-crow.html' title='Cocoa Bindings: mmm, crow'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-3664504562136900628</id><published>2007-03-17T10:58:00.000-07:00</published><updated>2007-03-18T00:21:35.382-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='cesta'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>Cocoa Bindings: @sum is O(n), even if you're nice to it.</title><content type='html'>My last post was very positive toward Cocoa Bindings.  A week later, you might say the honeymoon is over.&lt;br /&gt;&lt;br /&gt;They still do most of what I need, don't get me wrong -- it's the performance.  In profiles, whenever Cesta starts using an entire core on my MackBook Pro, Bindings is responsible for 80-90% of it.  (The harder stuff, like capturing, decoding, and constraint-checking a loaded ethernet link, is 2% or less.)&lt;br /&gt;&lt;br /&gt;I'm working on isolating each part of the problem, but here's a tidbit for today -- not from Bindings specifically, but from the Key-Value Coding system on which they're built (thanks for the correction, Scott).  (&lt;edit&gt;Update:&lt;/edit&gt; I Sharked my way to some of the other Bindings issues in my &lt;a href="http://cliffhacks.blogspot.com/2007/03/cocoa-bindings-mmm-crow.html"&gt;next post&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;The performance of @sum may surprise you.  Specifically, &lt;strong&gt;the @sum function is O(n) for the total size of your array, even if you distribute incremental updates using KVO.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This will come as no surprise if you're familiar with how KVC is implemented, but for those of us (me) hoping for a free ride, it's a bit of a downer.&lt;br /&gt;&lt;br /&gt;The backstory:&lt;br /&gt;&lt;br /&gt;I wanted a nice label on Cesta's summary view showing the number of bytes captured.  Lazy as I am, I decided to use Bindings: I created an NSTextField and bound it to the aggregate property "@sum.capturedSize" on my Capture Events NSArrayController.&lt;br /&gt;&lt;br /&gt;Now, I put a lot of work into distributing only incremental updates when new packets are captured.  My code diligently calls &lt;code&gt;willChange:valuesAtIndexes:forKey&lt;/code&gt; and &lt;code&gt;didChange:valuesAtIndexes:forKey&lt;/code&gt; with only the changed packets, so that observers don't have to reevaluate the whole array each time.  Hell, I even maintain separate state for each thread so that nobody sees new packets before they've received &lt;code&gt;willChange:&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;In short, I expected that any observer update that doesn't rely on &lt;em&gt;all&lt;/em&gt; the data (like @max would) would be, at worst, O(n) for the &lt;em&gt;number of changes&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;I was incorrect, as my debug traces show.  @sum is calling &lt;code&gt;capturedSize&lt;/code&gt; on &lt;em&gt;every&lt;/em&gt; packet, every time.&lt;br /&gt;&lt;br /&gt;This is one of three hotspots that cause Cesta's screen refreshes to be O(n) to the number of events captured.  The fix?  Drop the aggregate function and bind to a scalar property.  It's nearly trivial, but I'll include the code here for completeness.&lt;br /&gt;&lt;br /&gt;First, we add an ivar for the property, and a getter/setter pair:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@interface CSCaptureDocument : NSDocument {&lt;br /&gt;  ...&lt;br /&gt;  &lt;strong&gt;uint64_t _bytesCaptured;&lt;/strong&gt;&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;- (uint64_t)bytesCaptured;&lt;br /&gt;- (void)setBytesCaptured: (uint64_t)bytes;&lt;br /&gt;@end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then, we add the code for that getter and setter.  I won't post it here; there's a button to generate it.&lt;br /&gt;&lt;br /&gt;Then, we hook into the packet delivery code:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;- (void)frameSource: (CSFrameSource *)source receivedFrame: (CSFrame *)frame&lt;br /&gt;{&lt;br /&gt;    [_capture appendCaptureEvent: frame];&lt;br /&gt;    &lt;strong&gt;[self setBytesCaptured: _bytesCaptured + [frame capturedSize]];&lt;/strong&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then we simply re-bind the "Bytes Captured:" label to the &lt;code&gt;bytesCaptured&lt;/code&gt; property of the &lt;em&gt;document&lt;/em&gt;, rather than an aggregate property on the NSArrayController.  Voila -- instant 15% performance savings.&lt;br /&gt;&lt;br /&gt;(&lt;strong&gt;Edit:&lt;/strong&gt; as Scott points out in the comments, this behavior makes sense for @sum since there's nowhere to store the accumulator.  I've updated some of the text above to clarify that I'm not attacking @sum here, just pointing out my own very inappropriate use of it -- just in case someone else does the same thing and goes Googling for an explanation.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-3664504562136900628?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/3664504562136900628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=3664504562136900628' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/3664504562136900628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/3664504562136900628'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/03/cocoa-bindings-sum-is-on-even-if-youre.html' title='Cocoa Bindings: @sum is O(n), even if you&apos;re nice to it.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-7403711967897990324</id><published>2007-03-09T20:49:00.000-08:00</published><updated>2007-03-10T13:39:52.275-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cesta'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>Cesta lives!</title><content type='html'>I've been putting in a lot of work on Cesta, my network analyzer, due in no small part to continual goading from clee.  (He has a Mac now, and is trying to load it up with shiny Mac software.)&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/cesta-icon.png" width="128" height="128" style="float:right;"/&gt;&lt;br /&gt;&lt;br /&gt;I hadn't touched Cesta's code in over a year, and it was getting pretty crufty even then, so I didn't bother trying to modernize it.  Instead, I'm applying a marvelous technique I learned from John Brewer: TONSO, or Take Off and Nuke the Site from Orbit.&lt;br /&gt;&lt;br /&gt;(It's the only way to be sure.)&lt;br /&gt;&lt;br /&gt;The interesting thing is how &lt;em&gt;fast&lt;/em&gt; it's come along.  I bootstrapped the core system (with an Ethernet decoder) in an evening of work, while distracted by clee and Ben-from-Apple.  Starting from a clean slate really helps you reduce a system to its essentials -- and working in Objective-C didn't hurt either.  (Still one of my favorite languages of all time.)&lt;br /&gt;&lt;br /&gt;I've rebuilt &lt;em&gt;most&lt;/em&gt; of what the last Cesta generation could do, and killed off a number of ingrained-but-incorrect assumptions in the old domain model.  We should have feature-parity with Wireshark in the not-too-distant future, which is not a slam against the Wireshark devs by any means -- they're very smart.  No, it's a tribute to how easy developing Mac software in Objective-C has become.&lt;br /&gt;&lt;br /&gt;We're targeting Tiger-and-later with this rev, whereas the original Cesta worked all the way back to 10.2.  This makes things a lot cleaner: Mac OS X really is evolving at a breakneck pace, and while all the old APIs are still supported (and much faster), there are new ways of doing everything that are &lt;em&gt;so much better.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Case in point: Cocoa Bindings.  Much of the code in Cesta Of Old was dedicated to shuttling pieces of data onto, and off of, the screen.  I'm a user-interface geek, so it had to be blindingly fast, absolutely intuitive, and as fluid as Mac apps are expected to be -- and I paid for my high standards in code.&lt;br /&gt;&lt;br /&gt;Now?  There is no code.&lt;br /&gt;&lt;br /&gt;Using Cocoa Bindings, I wire up my UI widgets to my underlying domain model using Interface Builder, and the runtime figures out how best to move and cache the data.  The new Cesta UI is &lt;em&gt;entirely&lt;/em&gt; Bindings-driven, leaving the whole user interface as a thin projection of the underlying objects -- from the chooser that lets you pick the network interface(s) to capture from, right up to the three-paned packet list and dissector.&lt;br /&gt;&lt;br /&gt;If I have to, I can drop in optimizations where needed (Objective-C's category mechanism keeps it clean) -- but thus far, it hasn't been necessary.  Cocoa Bindings is fast; far faster than I expected, and they say it'll only get faster with time.  It doesn't break a sweat displaying hundreds of thousands of decoded packets in a table.  I am impressed.&lt;br /&gt;&lt;br /&gt;(I met the folks behind the Bindings API at a recent Cocoaheads meeting, and not only do they produce great things, they're also very friendly and tolerant of n00b questions.)&lt;br /&gt;&lt;br /&gt;Not having to hand-code the user interface has freed me up to work on more interesting parts of the application.  In the two weeks that this Cesta codebase has been under development, we've added features that I only dreamed of in the last rev.  For example, Cesta can now integrate data from any number of network interfaces in a single capture, and can attach and detach interfaces on the fly.  (These changes are even recorded inline, right in the capture, for future reference.)&lt;br /&gt;&lt;br /&gt;It's also grown a general framework for finding, highlighting, and explaining problems in packets.  If an IP checksum is wrong, for example, it's highlighted in the UI, and the user can see a localized explanation of the issue.&lt;br /&gt;&lt;br /&gt;We &lt;em&gt;have&lt;/em&gt; found one issue, however.  clee is totally new to Cocoa, just having cracked open the Hillegass book, and the Cesta codebase is total greek to him -- even though he's a very sharp programmer, fluent in half a dozen languages.&lt;br /&gt;&lt;br /&gt;I can't blame him.  The main difference between this Cesta and the last is that I now fully grok the Cocoa application/document architecture.  It took me a couple years of diligent study to get everything right (because some important parts of it are not terribly well-documented -- and I didn't have the Hillegass book).  To a newcomer, the control flow is &lt;em&gt;almost entirely opaque&lt;/em&gt;.  Sure, you can see that CSCaptureDocument seems to be some sort of document that holds a capture, but it's never created anywhere -- and neither are most of the other classes!  How on earth do they talk to each other?&lt;br /&gt;&lt;br /&gt;The answer, of course, is that a good chunk of the application logic is effectively hidden.  It's not in the source code; it's in property list files, in the Interface Builder nibs, in interactions with closed-source frameworks.  To a programmer used to programming, well, &lt;em&gt;code&lt;/em&gt;, and accustomed to fully open-source systems, Cocoa can be pretty mysterious.  To really understand a Cocoa application, particularly one that has drank as deeply of the Kool-Aid as Cesta has, one must understand all these non-code resources -- and, in some cases, read the API docs on every dependent class, trying to figure out who calls what delegate method and why.&lt;br /&gt;&lt;br /&gt;Ironically, the loose coupling that makes control flow hard to understand is also one of Cocoa's greatest strengths.  (Though part of the problem -- possibly a large part -- is Xcode, which is firmly lodged about six years behind the IDE state-of-the-art.  From a Java perspective, it feels like my 1999 work in Forte, rather than my 2007 work in Eclipse.)&lt;br /&gt;&lt;br /&gt;To diverge even further from the alleged topic of this post, this also worries me on my applications at work.  Us loosely-coupled object systems guys are leaning pretty heavily on dependency injection and event-driven applications these days, and it may come to the point where the only way to understand the flow of control is to step through the app in a debugger.  Not an ideal solution.&lt;br /&gt;&lt;br /&gt;Anyway.  Coming back around to Cesta, there's one other point of interest: we'll be open-sourcing this version, most likely under a BSD license.  I've been out of real open source development for too long.  It'll be good to be back.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-7403711967897990324?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/7403711967897990324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=7403711967897990324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7403711967897990324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/7403711967897990324'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/03/cesta-lives.html' title='Cesta lives!'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-4295174957220452742</id><published>2007-02-24T13:14:00.000-08:00</published><updated>2007-02-24T13:39:59.057-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cesta'/><category scheme='http://www.blogger.com/atom/ns#' term='mongoose'/><category scheme='http://www.blogger.com/atom/ns#' term='machine learning'/><title type='text'>The wheel of hobbies spins on.</title><content type='html'>This is a sort of omnibus update for all my various projects, in case anyone's watching. :-)&lt;br /&gt;&lt;br /&gt;My spare-time projects tend to be fueled by interest from others.  If I'm doing them just for me, I'll hack on it to solve some interesting set of problems, and then leave them unfinished.  The partially-finished systems are useful to &lt;i&gt;me&lt;/i&gt;, and solve my problems; packaging and publishing them is only worth it if they'll be useful to &lt;i&gt;others&lt;/i&gt;.  I do enough software-polishing in my day job that I have a hard time making it a hobby unless I'm helping people in the process.&lt;br /&gt;&lt;br /&gt;Speaking of the day job, my workload has increased dramatically since about October.  My team has shrunk, but our responsibilities haven't.  I'm enjoying it, but it cuts into my spare time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PropellerForth has stalled due to profound lack of interest from the Propeller community, though I've suddenly (past week or so) gotten a bunch of emails about it.  Thus, I may pick it back up, or at least publish the sources so others can carry the torch.  (I never got around to publishing before.)  I still don't know of anyone using propasm, which is ironic, since I actually packaged it -- the sources are available, and have near-100% test coverage.&lt;br /&gt;&lt;br /&gt;I've done a lot of rethinking of Mongoose.  I've been working with some of the new batch of next-generation multi-paradigmatic languages, like Scala, but none of them are heading in the direction I want.  I'm still using Mongoose primarily to prove some points, and not intending it to be the "next big thing" -- but at the same time, I've been looking at targeting it to existing VMs, with the hopes of achieving interoperability with some last-gen languages.  (And not having to maintain my own VM.  I hate C++.)&lt;br /&gt;&lt;br /&gt;The robots have been dormant lately, but DPR still boots and works (imagine, a Linux system that still works after several months of inattention).  I've been learning a &lt;i&gt;lot&lt;/i&gt; about machine learning lately in my day job, and I'm hoping to rewrite some of DPR's personality using new techniques like fuzzy associative memories.  I'll post here if I get around to it.&lt;br /&gt;&lt;br /&gt;So, what have I been hacking on?  Strangely enough, Cesta -- my network analyzer, which I've left untouched for nearly a year.  My brain keeps coming back to it, because it lets me do the sort of stuff I don't get to do at work (like UI and interaction design), while still presenting a lot of juicy hard problems (like my fuzzy protocol decoding ideas).  I'm applying what I learned from the Mongoose compiler to reworking Cesta's protocol decoding layer, enabling it to synthesize new decoders on the fly.&lt;br /&gt;&lt;br /&gt;For example, take TCP.  TCP connections contain no indication of the protocol they're carrying -- sure, the connection is to port 80, but that's not a guarantee that it's carrying HTTP.&lt;br /&gt;&lt;br /&gt;Previously, my solution was brute-force: try to decode every known TCP protocol, eliminating them one by one as they reject the data as malformed.  Two years ago I was already looking at more efficient ways to do this, but got caught up in the fun stuff like graph rendering and UI design.&lt;br /&gt;&lt;br /&gt;In my reworking of the protocol decoding, I came across a better way.  Protocols are defined declaratively using a &lt;i&gt;protocol definition file&lt;/i&gt;, which Cesta compiles into decoder code -- and by synthesizing the constraints and layouts of all protocols known to be carried in TCP connections, it can generate a state machine that allows quick and efficient payload-type detection.  (And, thanks to the dynamic code generation techniques I learned for Mongoose, I think I can compile the code on the fly without e.g. calling out to gcc.)&lt;br /&gt;&lt;br /&gt;If this sounds like massive overkill, you're right -- which is where the machine learning comes in.  Using the fuzzy associative memory techniques I've learned recently, Cesta can &lt;i&gt;learn&lt;/i&gt; what protocols are most likely to be sent over a given port, and optimize the decoder appropriately.  For example, a TCP connection to port 80 is &lt;i&gt;pretty likely&lt;/i&gt; to be HTTP, so we can try decoding it as such until proven wrong -- a technique I call &lt;i&gt;speculative decoding&lt;/i&gt;.  If the guess proves wrong, we can try the next-most-likely protocol, or fall back to the synthetic every-protocol decoder I described above.&lt;br /&gt;&lt;br /&gt;As a side effect, we get service-type identification.  If Cesta learns that a port &lt;i&gt;on a particular host&lt;/i&gt; seems to be speaking HTTP or SSHv2, it records this in the fuzzy memory, and we can present this to the user.&lt;br /&gt;&lt;br /&gt;Multiplexed ports or changes in service don't present a problem for this either: it has no difficulty describing a port as "80% HTTP, 20% SSH" if something weird is going on (such as dynamic port mappings on a NAT).&lt;br /&gt;&lt;br /&gt;This is complicated -- rather more complicated, in fact, than any network analyzer I've ever used -- but I understand all the techniques involved, and I think I can pull it off.  Once there's code, I'll post it here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4295174957220452742?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4295174957220452742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4295174957220452742' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4295174957220452742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4295174957220452742'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/02/wheel-of-hobbies-spins-on.html' title='The wheel of hobbies spins on.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-2622480035684640626</id><published>2007-01-15T22:06:00.000-08:00</published><updated>2007-01-15T22:10:40.438-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rc'/><title type='text'>Helicam v1.1 initial flight</title><content type='html'>I've rebuilt the camera rig and done a lot of tuning to the helicopter, so I'm a bit more confident flying in wind -- but still skittish, as this video shows.&lt;br /&gt;&lt;br /&gt;New in this video: the on-board mic is working, and I have remote control of the camera's tilt angle.  (I MacGuyver'd an articulating mount out of some corrugated cardboard, a paperclip, a spare 6-gram servo, and some mylar from a Teavana bag.)&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt;&lt;param name="movie" value="http://www.youtube.com/v/eULx6KJH2as"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/eULx6KJH2as" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-2622480035684640626?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/2622480035684640626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=2622480035684640626' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/2622480035684640626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/2622480035684640626'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/01/helicam-v11-initial-flight.html' title='Helicam v1.1 initial flight'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-4685423466005213236</id><published>2007-01-13T10:38:00.000-08:00</published><updated>2007-01-13T10:44:34.488-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rc'/><title type='text'>CX-Cam flight test video</title><content type='html'>Over the holidays, I was working on something rather different.  After much experimentation, tuning, and part-hunting, I now have a small aerial camera platform.  This is something I've wanted to do since at least middle school, and technology has finally caught up.&lt;br /&gt;&lt;br /&gt;The neat part, to me, is that it's nearly off-the-shelf hardware.  It's based around a small radio-controlled helicopter and a commercially available wireless camera.  (Both are modified, but not extensively.)&lt;br /&gt;&lt;br /&gt;Perhaps most importantly, this is something that I'm having fun with, and that others are interested in &amp;mdash; a nice vacation from my language/Forth work, which nobody ever comments on. :-)&lt;br /&gt;&lt;br /&gt;Here's a video.&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt;&lt;param name="movie" value="http://www.youtube.com/v/TzYJiTmtZyg"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/TzYJiTmtZyg" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-4685423466005213236?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/4685423466005213236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=4685423466005213236' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4685423466005213236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/4685423466005213236'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2007/01/cx-cam-flight-test-video.html' title='CX-Cam flight test video'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-116300503429188875</id><published>2006-11-08T08:40:00.000-08:00</published><updated>2006-11-08T08:57:14.593-08:00</updated><title type='text'>More on PropellerForth</title><content type='html'>I mentioned in my last post that I hoped to optimize PropellerForth, and get it running faster than 1.7 million (small) words per second (MWPS).  Well, this may not be possible.  Here's my thinking:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Executing any word requires at least two memory reads: reading the word out of the instruction thread, and reading that word's code field.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Most interesting words require at least one additional memory read (such as pulling a second argument off the parameter stack, or reading an inline argument from the instruction thread).  Memory writes are less common, since the top of stack is in a register.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;A memory read can only occur once every 16 cycles.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;At 80MHz, we get 5 million memory reads per second.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;At 2-3 memory accesses per word, we max out at 1.67-2 million words per second.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Thus, for an indirect-threaded interpreter on the P8X32 (the current Propeller incarnation), I'm already nudging up against the theoretical maximum.&lt;br /&gt;&lt;br /&gt;Of course, &lt;i&gt;each core&lt;/i&gt; can only access memory every 16 cycles &amp;mdash; so the Propeller can support eight simultaneous 1.7MWPS Forth kernels.&lt;br /&gt;&lt;br /&gt;On a traditional architecture, the next step would be to ditch indirect threading for either direct or subroutine threading &amp;mdash; either of which potentially eliminates a memory access from every word.  However, on the Propeller this won't work:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Executable code can live only within the 2KB "cog-local" RAM attached to each core.  Thus, all CFAs point into this region, not into shared RAM where the dictionary lives.  As a result, a single jump instruction cannot target both a machine code word and a user word &amp;mdash; so subroutine threading is out.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Likewise, I cannot simply jump to the CFA of a word &amp;mdash; first it would have to be loaded into cog-local RAM.  Thus, direct threading would probably incur more overhead, not less, from moving each word across address spaces.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I'm investigating other ways of cutting my memory access frequency.  Stay tuned.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If the Propeller folks were to ask me for advice on their next architecture (which they haven't), I would make the following suggestions:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Indirect addressing of cog-local RAM.  The current architecture treats local RAM as a register file, and (as with most register files) won't indirectly address it through a register.  This means all task stacks have to live in shared RAM, slowing things down tremendously.  (The stacks can actually live in local RAM, but it requires self-modifying code and ends up more expensive than just using the slow RAM.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Make the local and shared RAM address spaces disjoint.  Combined with the indirect addressing, this would allow a single instruction to read from either local or shared RAM (possibly incurring greatly increased latency).  This would make direct-threaded interpreters possible.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Include sign-extending variants of &lt;code&gt;rdword&lt;/code&gt; and &lt;code&gt;rdbyte&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Orthogonality is all well and good, but I really miss auto-increment addressing.  Being able to auto-increment/decrement a register after a &lt;code&gt;rdlong&lt;/code&gt; or &lt;code&gt;wrlong&lt;/code&gt; would cut the size of my Forth kernel by nearly 25%, and keep me from missing some hub access windows.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-116300503429188875?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/116300503429188875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=116300503429188875' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116300503429188875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116300503429188875'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/11/more-on-propellerforth.html' title='More on PropellerForth'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-116283349795558912</id><published>2006-11-06T08:57:00.000-08:00</published><updated>2006-11-06T15:54:41.673-08:00</updated><title type='text'>PropellerForth</title><content type='html'>Regular readers know my take on the Parallax Propeller microcontroller: neat, 8-core silicon hampered by a platform-specific, very limited IDE (really more of an editor with a &lt;i&gt;Load&lt;/i&gt; button) and a programming language I don't much care for.&lt;br /&gt;&lt;br /&gt;In the hopes of solving both these issues in one swell foop, I've started work on an ANS Forth for the Propeller &amp;mdash; creatively titled PropellerForth.  For folks who haven't used Forth, it is simultaneously the most bewildering and liberating programming environment you'll ever use &amp;mdash; a computational boot-to-the-head of the same degree as Lisp or Smalltalk.  Like these languages, Forth is generally written entirely in itself, and the user can modify even the fundamental operations at runtime in an interactive environment.&lt;br /&gt;&lt;br /&gt;The main difference: even modern Forths tend to fit happily in 8K of RAM.  (Mine's a little larger than this, now, because I've added in some luxurious libraries.)&lt;br /&gt;&lt;br /&gt;Currently, my system image comes in at 8,372 bytes, including all buffers and stacks for the bootstrap task.  It executes 1.7 million words (small words) per second at 80Mhz &amp;mdash; not a speed demon, but I've still got a lot of room for optimization.  It was at 1.4 milion wps yesterday.&lt;br /&gt;&lt;br /&gt;The oddities of the Propeller architecture have made this a little interesting:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;It's an old-style, string-of-addresses indirect threaded Forth.  This is necessary because the more modern styles such as direct or subroutine threading assume you can jump to instructions in the dictionary's data space; the Propeller can't.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The Propeller has no hardware stacks, or indirect addressing of its fast (local) RAM.  Thus, the stack is emulated with slow (shared) RAM, entirely in software.  This has required a lot of careful tuning.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The Propeller has no hardware peripherals, other than some counters.  All I/O, including the serial console, is implemented by the Forth kernel.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Forth was designed for multiuser multitasking on single-core machines, and later expanded to multiuser multitasking on SMP machines.  As an embedded system, the Propeller needs &lt;i&gt;single-user&lt;/i&gt; multitasking on an eight-core chip &amp;mdash; eight cores sharing a dictionary and data space.  This means things like semaphores all of a sudden appear in the standard library.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Forth is intoxicating.  Once the system is bootstrapped (which required a couple kilobytes of assembler, most of which I generated with some scripts &amp;mdash; as I am wont to do), development proceeds exponentially, by defining each layer in the system in terms of the previous.&lt;br /&gt;&lt;br /&gt;I believe that every aspiring (or experienced) computer programmer should write a Forth at some point, as a sort of rite of passage.  It's challenging, but not because it's hard: because it requires some pretty fundamental paradigm shifts.  Writing a Forth will bring you many &lt;i&gt;Aha!&lt;/i&gt; moments, and watching the language define itself is quite a trip.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-116283349795558912?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/116283349795558912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=116283349795558912' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116283349795558912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116283349795558912'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/11/propellerforth.html' title='PropellerForth'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-116156951887454616</id><published>2006-10-22T19:01:00.000-07:00</published><updated>2006-10-23T09:37:30.980-07:00</updated><title type='text'>propasm, the Propeller Assembler</title><content type='html'>I've released &lt;a href="http://www.cliff.biffle.org/software/propeller/propasm/"&gt;propasm&lt;/a&gt;, my assembler for the &lt;a href="http://www.parallax.com/propeller/"&gt;Parallax Propeller&lt;/a&gt; eight-core microcontroller.  Unlike the Parallax-provided assembler, it:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Runs on practically anything;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Can be automated from scripts or Makefiles;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Provides really good feedback;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Supports characters outside of US English;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Is written in Java;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Will be open-sourced shortly.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;This was an interesting project for me, because it involved a number of separate areas of my brain.  This was my first hand-written traditional parser; I've written plenty of parsers before, but this one is broken into a traditional scanner/lexer and recursive-descent parser.  Since I was writing the parser by hand, I was able to make the error messages clear and specific &amp;mdash; something generated parsers often lack.&lt;br /&gt;&lt;br /&gt;I also had to reverse-engineer the binary format and parts of the instruction set, as Parallax's documentation on both is spotty.&lt;br /&gt;&lt;br /&gt;Since it's in Java, rather than x86 assembler (like Parallax's), it's somewhat slower.  It takes all of 10ms to load, parse, wire, and write out a decent-sized program.&lt;br /&gt;&lt;br /&gt;...of course, to use Parallax's, I have to boot Windows, start an IDE, open my text file, and click four times in a menu.  I think propasm wins overall. :-)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; I'm already on my first point release; I'd made an error on the I/O code that caused UTF-8 to be mangled on some platforms.  Fortunately, my test case using &amp;#x30A6;&amp;#x30FC;&amp;#x30ED;&amp;#x30F3;&amp;#x8336; as a variable name failed.  If only I'd had the tests written when I released... :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-116156951887454616?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/116156951887454616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=116156951887454616' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116156951887454616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116156951887454616'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/10/propasm-propeller-assembler.html' title='propasm, the Propeller Assembler'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-116071095710371985</id><published>2006-10-12T20:27:00.000-07:00</published><updated>2006-10-12T20:46:48.440-07:00</updated><title type='text'>Mongoose Reborn</title><content type='html'>In any other context, this would probably be a bad thing:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;Mnemosyne:~/Projects/m3/vm cbiffle$ ./vmtest test.mgm &lt;br /&gt;HEAP: 0x2800400 - 0x2801400&lt;br /&gt;HALT&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;But in this case, coming to a screeching halt is exactly what I wanted.&lt;br /&gt;&lt;br /&gt;M3VM, the third virtual machine for Mongoose, has officially booted some code (even if that code was a single halt-catch-fire instruction).  This is the third time in two years that I've rewritten the VM from scratch, proving hands-down that I have very weird hobbies.&lt;br /&gt;&lt;br /&gt;This time, it's in C++, which has been trippy.  I haven't written any large C++ apps in three years, and I really dislike the language &amp;mdash; but it happens to be ideal for this, so I'm ignoring the nasty bits and making do.  M2VM was written in GNU C, and M3VM isn't much different &amp;mdash; but I can bundle my functions into classes now.  For an object-head like me, that's a big plus.&lt;br /&gt;&lt;br /&gt;Working with a higher level of abstractions has also let me focus less on the details, and more on the goal.  I've built the object model the way I wanted it, and I'm working on the neat Self-like optimizations I've had planned.&lt;br /&gt;&lt;br /&gt;To get to the triumphant HALT, the machine had to &lt;ul&gt;&lt;br /&gt;&lt;li&gt;Load the base module, in the new Mongoose Module format;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wire all the objects together, including the ones that have to exist in phantom form (like Object, Class, and Array) before they are loaded;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Start the interpreter, written in Mongoose and translated by Ruby to C++;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Resolve the entry-point method by name;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Fall over screaming.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The rewrites are quicker each time.  Not only is the line count of M3VM significantly lower than M2VM, it took less than a week (part-time) to write.  It's also considerably smarter &amp;mdash; the garbage collector, my fourth, has learned a lot of neat tricks, and runs in milliseconds even for fragmented 64MB heaps.&lt;br /&gt;&lt;br /&gt;Soon, I'll have the compiler working, so I can quit writing code in a hex editor. :-)&lt;br /&gt;&lt;br /&gt;(P.S. If you, too, are authoring files in a hex editor, you need to go download &lt;a href="http://ridiculousfish.com/hexfiend/"&gt;Hex Fiend&lt;/a&gt;.  Seriously.  It is, hands down, the best hex editor I've ever used &amp;mdash; including the ones I've written.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-116071095710371985?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/116071095710371985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=116071095710371985' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116071095710371985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/116071095710371985'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/10/mongoose-reborn.html' title='Mongoose Reborn'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-115807993483734695</id><published>2006-09-12T09:34:00.000-07:00</published><updated>2006-09-14T20:57:20.366-07:00</updated><title type='text'>Type Inferencing for Mongoose</title><content type='html'>After a few months of meditation, Mongoose's type system has finally come together.  It lives in a several-dozen-page VoodooPad document right now, but I'll summarize it here.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Protocol-based,&lt;/em&gt; the OO equivalent of structural typing.  A "type" describes an object's externally-visible operations, not where it gets its code.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Pragmatic.&lt;/em&gt;  Supports both "subclass-to-specialize" (as in Eiffel) and "subclass-to-extend" (as in every other OO language), without the holes in Eiffel's type system.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Simple.&lt;/em&gt;  All the safety and flexibility of Java's generics, the loose hierarchy of duck-typed languages like Python or Ruby, but with very thorough static checking (if you so desire) &amp;mdash; and yet, far simpler to learn than Java's type system.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Optional.&lt;/em&gt;  'Nuff said.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Some of the problems I've managed to solve recently include:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;How substitutability (in the Liskov sense) works in a protocol-typed language, with an adaptation of co-contravariance.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;How to handle union and intersection types.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;How to run an inferencer over the whole shebang.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;This post is really focused on that last point: I got the inferencer working for simple cases.&lt;br /&gt;&lt;br /&gt;Take the following code snippet, which defines a simple stream class that produces the Fibonacci numbers.  To fill in for the standard library, this snippet also defines a protocol Integer (the protocol of numeric literals), and stubs out a protocol Boolean (the protocol of the literals &lt;em&gt;true&lt;/em&gt; and &lt;em&gt;false&lt;/em&gt;).&lt;br /&gt;&lt;br /&gt;When reading, remember that, like Smalltalk, the caret character ^ means "return."&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;protocol Integer {&lt;br /&gt; (* A method named "+", which takes and returns an Integer *)&lt;br /&gt; method + other (Integer) ^ (Integer).&lt;br /&gt;}&lt;br /&gt;protocol Boolean {&lt;br /&gt;}&lt;br /&gt;class FibonacciStream {&lt;br /&gt; var a := 1.&lt;br /&gt; var b := 1.&lt;br /&gt;&lt;br /&gt; method hasNext [&lt;br /&gt;  ^true.&lt;br /&gt; ]&lt;br /&gt;&lt;br /&gt; method next [&lt;br /&gt;  var c := self twoValuesAgo + b.&lt;br /&gt;  a := b.&lt;br /&gt;  b := c.&lt;br /&gt;  ^c.&lt;br /&gt; ]&lt;br /&gt;&lt;br /&gt; (* This method is here only to introduce some indirection. *)&lt;br /&gt; method twoValuesAgo [&lt;br /&gt;  ^a.&lt;br /&gt; ]&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;(Long-time readers will note that, yes, the syntax has changed &lt;em&gt;yet again&lt;/em&gt;.)&lt;br /&gt;&lt;br /&gt;Of note: the FibonacciStream (the actual user code here) has no type annotations at all.&lt;br /&gt;Also of note (at least because it confused the early inferencer): The types of &lt;em&gt;a&lt;/em&gt;, &lt;em&gt;b&lt;/em&gt;, and &lt;em&gt;c&lt;/em&gt; all depend on one another.&lt;br /&gt;&lt;br /&gt;Despite the lack of user type declarations, the inferencer actually has a lot to work with: it knows that &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt; begin life as Integers, and it knows the signature of Integer's "+" method.  This is sufficient to derive all the types in this class, as you can see in the output from the inferencer:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;protocol Integer {&lt;br /&gt;  method + other (Integer) ^(Integer)&lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;protocol Boolean {}&lt;br /&gt;class FibonacciStream {&lt;br /&gt;  var a (Integer) := 1.&lt;br /&gt;  var b (Integer) := 1.&lt;br /&gt;  method hasNext ^(Boolean)&lt;br /&gt;  [&lt;br /&gt;    ^true.&lt;br /&gt;  ]&lt;br /&gt;  method next ^(Integer)&lt;br /&gt;  [&lt;br /&gt;    var c (Integer) := self twoValuesAgo + b.&lt;br /&gt;    a := b.&lt;br /&gt;    b := c.&lt;br /&gt;    ^c.&lt;br /&gt;  ]&lt;br /&gt;  method twoValuesAgo ^(Integer)&lt;br /&gt;  [&lt;br /&gt;    ^a.&lt;br /&gt;  ]&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The inferencer has different formatting tastes than I do; it seems to use two spaces instead of tabs, and put its brackets on their own line.  I'll fix this egregious error later. :-)&lt;br /&gt;&lt;br /&gt;The inferencer has some other neat tricks, not shown here (because they mostly crop up in really weird designs).  It can handle variables that change type over their lifetime, either by synthesizing a union-type or by splitting the variable, SSA-style.  It also does all sorts of neat things with Mongoose's generics system, but I'll write more on that once I get the damn thing working. :-)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; The case I cite above, where a variable changes type over time, is now a warning.  You can use a type declaration to express your intention if you really want it to happen, but I find that (in Ruby, at least, which is the most similar language I work in) it's almost always a bug.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-115807993483734695?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/115807993483734695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=115807993483734695' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/115807993483734695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/115807993483734695'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/09/type-inferencing-for-mongoose.html' title='Type Inferencing for Mongoose'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-115134755341684499</id><published>2006-06-26T11:43:00.000-07:00</published><updated>2006-06-26T11:45:53.430-07:00</updated><title type='text'>ASCIIvision</title><content type='html'>After a lot of tinkering, I've got the Gumstix talking to my CMUcam2.&lt;br /&gt;&lt;br /&gt;I started out working with CMU's Java interface code, but it's abysmal.  It's like an exercise in how not to write Java.  So, scratch that.&lt;br /&gt;&lt;br /&gt;I worked in C for a bit, thinking that it would be nice to eliminate the JVM from my cramped root filesystem.  Then, I remembered how much IO programming in C can suck, and went back to Java.&lt;br /&gt;&lt;br /&gt;So, now, I've written my own interface library for the CMUcam.  I quickly got tired of printing numbers and guessing whether or not I had configured the camera properly; I wanted an image, dammit.  But on a tiny device, with no display, how do you generate images?&lt;br /&gt;&lt;br /&gt;Using ASCII, of course!&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/ascii-hand.png" width="295" height="175"/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-115134755341684499?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/115134755341684499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=115134755341684499' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/115134755341684499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/115134755341684499'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/06/asciivision.html' title='ASCIIvision'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-115103262069174382</id><published>2006-06-22T19:47:00.000-07:00</published><updated>2006-06-22T20:18:54.216-07:00</updated><title type='text'>Gumstix -- first experiences</title><content type='html'>I've finally given in and bought a single-board computer from &lt;a href="http://www.gumstix.com/"&gt;Gumstix&lt;/a&gt;.  It's amusingly dinky.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cliff.biffle.org/pictures/gumstix.jpg" width="320" height="240"/&gt;&lt;br /&gt;&lt;br /&gt;That thar's a 400MHz RISC machine, with 16MB of on-board Flash, 64MB of RAM, and Bluetooth (with antenna attached).  It comes out of the box running Linux.  I have daughterboards that add RS-232-level serial ports, USB client, and a CompactFlash slot for disk or WiFi.&lt;br /&gt;&lt;br /&gt;I've been working with the board for a few days now, and thought it time to post my first experiences.&lt;br /&gt;&lt;br /&gt;All in all, I am damn pleased.  I haven't had this much fun with an embedded system in years.  However, there's a topic that deserves an initial rant.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The Support Rant&lt;/h2&gt;&lt;br /&gt;First thing: if you want solid support or well-organized technical information, &lt;em&gt;look elsewhere.&lt;/em&gt;  Gumstix, the company, has no obvious contact information; when I finally tracked down an email address, they redirected me to a public mailing list.&lt;br /&gt;&lt;br /&gt;Ah, yes, I remember what running Linux is like.&lt;br /&gt;&lt;br /&gt;The good news is, the mailing list is very helpful.  I'm sure my questions had been asked a dozen times before, but I received not a single RTFM.&lt;br /&gt;&lt;br /&gt;Which is fortunate, as there's no M to FR -- &lt;em&gt;there is no manual.&lt;/em&gt;  All documentation on the Gumstix and accessories, from features and drivers to pinouts and compatibility matrices, is hidden in a Wiki.  And hidden it is.  This is one of the worst-organized Wikis I have ever seen, with several pages on any given topic, each of which claims to be canonical and all of which are wrong.&lt;br /&gt;&lt;br /&gt;Example: there are pages in the Wiki that discuss setting up the Gumstix development environment on Mac OS X.  Don't try it.   They're out of date by nearly two years, and will have you check out a branch of the repository that's about that old.  Not only do the directions not work, you'll be stuck with an ancient system with very few of the optional packages available.&lt;br /&gt;&lt;br /&gt;Example: the PXA255, the processor at the heart of this board, has four UARTs.  I remembered this from hacking Linux on my PXA255-powered iPaq years back.  You can get various combinations of these UARTs on various daughterboards, sometimes with level-shifters, sometimes at TTL level.  However, the actual online store, where you would go to buy such things, doesn't have this information.  No, you must dredge the Wiki.&lt;br /&gt;&lt;br /&gt;This is includes pretty damn basic details, like which UART the onboard Bluetooth is attached to.  (It's the BTUART pins, for those arriving here by Google, &lt;em&gt;but the HWUART driver&lt;/em&gt;, routed to the BTUART pins.  So, by default, both the HWUART and BTUART are occupied.  You can, however, route the HWUART to auxiliary pins.)  Likewise, I had to trace schematics to determine which UART their optional GPS would occupy.  (It's the STUART, routed through the FIR pins.)&lt;br /&gt;&lt;br /&gt;And, here's the kicker: my original board configuration &lt;em&gt;wouldn't have worked&lt;/em&gt;, though there's no information on the website to indicate this.  Enabling both Bluetooth and the CompactFlash board means the HWUART can no longer be used for anything but Bluetooth.  Add the GPS module and I'm down to a single serial port -- not enough for what I'm doing.&lt;br /&gt;&lt;br /&gt;Fortunately, I'm pretty familiar with the PXA255 and can trace schematics.  Otherwise, this would have been a rude surprise.&lt;br /&gt;&lt;br /&gt;Okay, now that that's out of the way:&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The Good Stuff&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Getting into the Gumstix via Bluetooth from my Mac was trivial.  I had a wireless console in well under five minutes.  It goes a little something like this:&lt;br /&gt;1. Pair with the Mac from the Gumstix side, since the Gumstix (by default) can't interactively request a PIN.  Use &lt;code&gt;hcitool scan&lt;/code&gt; to find your Mac, &lt;code&gt;hcitool cc [ your address ]; hcitool auth [ your address ]&lt;/code&gt; to pair; the default PIN is 1234.&lt;br /&gt;2. On the Mac, open Bluetooth Preferences, find the Gumstix in the Devices tab, and click Edit Serial Ports.&lt;br /&gt;3. Accept the defaults it offers you.&lt;br /&gt;4. Connect from your favorite terminal emulator; the port is named (by default) Gumstix-1, or /dev/tty.Gumstix-1, to you Unixy types.&lt;br /&gt;&lt;br /&gt;All in all, the quality of the Bluetooth support (via BlueZ) blows my mind.&lt;br /&gt;&lt;br /&gt;The Gumstix guys have also put together a very nice Linux distribution.  It smells like it's based on &lt;a href="http://familiar.handhelds.org/"&gt;Familiar&lt;/a&gt; -- which is fine by me, having used it in the past.  If you have a recent Linux box, you are a Subversion-checkout away from cross-compiling your own images to the board.&lt;br /&gt;&lt;br /&gt;They've even got interactive menus for selecting what packages and options to compile into the image; their scripts will go out and fetch the requisite sources and compile everything automatically.  Very slick, and it works far better than the buildroot for Familiar did.  I had JamVM for Java and the GNU Classpath libraries installed with almost no work at all.&lt;br /&gt;&lt;br /&gt;Now I just need the parts to interface this bad boy to the robot....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-115103262069174382?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/115103262069174382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=115103262069174382' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/115103262069174382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/115103262069174382'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/06/gumstix-first-experiences.html' title='Gumstix -- first experiences'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114879029995215787</id><published>2006-05-27T20:29:00.000-07:00</published><updated>2006-05-27T21:35:07.066-07:00</updated><title type='text'>The Mongoose syntax evolves, with a comparison to Java</title><content type='html'>I'm tinkering on a new syntax for Mongoose, which incorporates the type system I've spoken of in the past.&lt;br /&gt;&lt;br /&gt;As an example, let's look at a simple Java class, and how we would implement the same class in Mongoose.&lt;br /&gt;&lt;br /&gt;This class is called Filter, and comes from some dataflow-style processing code of mine.  Basically, this code constructs a pipeline of producers and consumers, each of which does some processing or conversion of the data.  Producers will &lt;em&gt;finish&lt;/em&gt; when they have completed processing and will produce no further output.  This &lt;em&gt;finished&lt;/em&gt; status propagates forward through the other stages, and is used at the terminal stage(s) to trigger report generation or aggregation.&lt;br /&gt;&lt;br /&gt;The Filter can sit between some number of Producers and some number of Consumers.  It tests its input, and if it matches some condition, passes it on.&lt;br /&gt;&lt;br /&gt;First, the groundwork.  These interfaces implement the Producer/Consumer pattern, with some additional signalling for when processing at each stage has completed.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;interface Producer&amp;lt;E&gt; {&lt;br /&gt;  void addConsumer(Consumer&amp;lt;E&gt; consumer);&lt;br /&gt;  void removeConsumer(Consumer&amp;lt;E&gt; consumer);&lt;br /&gt;  boolean isFinished();&lt;br /&gt;}&lt;br /&gt;interface Consumer&amp;lt;E&gt; {&lt;br /&gt;  void consume(Producer&amp;lt;E&gt; source, E input);&lt;br /&gt;  void producerFinished(Producer&amp;lt;E&gt; producer);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pretty straightforward.  Now, I have a lot of different implementations of Producer, some of which need to inherit from existing classes (generally for legacy reasons).  Thus, I package up the basic Producer functionality in a ProducerSupport class, to which Producers can delegate most operations.  It has two utility methods, &lt;code&gt;emit&lt;/code&gt; and &lt;code&gt;finish&lt;/code&gt;, that the owning Producer can call to control its operation.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class ProducerSupport&amp;lt;E&gt; implements Producer&amp;lt;E&gt; {&lt;br /&gt;  final Producer&amp;lt;E&gt; owner;&lt;br /&gt;  final Set&amp;lt;Consumer&amp;lt;E&gt;&gt; consumers = new CopyOnWriteArraySet&amp;lt;Consumer&amp;lt;E&gt;&gt;();&lt;br /&gt;  volatile boolean finished = false;&lt;br /&gt;&lt;br /&gt;  ProducerSupport(Producer&amp;lt;E&gt; owner) { this.owner = owner; }&lt;br /&gt;&lt;br /&gt;  void addConsumer(Consumer&amp;lt;E&gt; consumer) { consumers.add(consumer); }&lt;br /&gt;  void removeConsumer(Consumer&amp;lt;E&gt; consumer) { consumers.remove(consumer); }&lt;br /&gt;  boolean isFinished() { return finished; }&lt;br /&gt;&lt;br /&gt;  void emit(E output) {&lt;br /&gt;    for(Consumer&amp;lt;E&gt; consumer : consumers) consumer.consume(owner, output);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void finish() {&lt;br /&gt;    finished = true;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, the Filter class.  I've cut some corners in this example &amp;mdash; for example, it supports only one producer &amp;mdash; but bear with me.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Filter&amp;lt;E&gt; implements Consumer&amp;lt;E&gt;, Producer&amp;lt;E&gt; {&lt;br /&gt;  final ProducerSupport&amp;lt;E&gt; ps = new ProducerSupport&amp;lt;E&gt;(this);&lt;br /&gt;  final Predicate&amp;lt;E&gt; predicate;&lt;br /&gt;&lt;br /&gt;  Filter(Predicate&amp;lt;E&gt; predicate) {&lt;br /&gt;    this.predicate = predicate;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void consume(Producer&amp;lt;E&gt; source, E input) {&lt;br /&gt;    if(predicate.matches(input)) emit(input);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void producerFinished(Producer&amp;lt;E&gt; producer) {&lt;br /&gt;    ps.finish();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void addConsumer(Consumer&amp;lt;E&gt; consumer) { ps.addConsumer(consumer); }&lt;br /&gt;  void removeConsumer(Consumer&amp;lt;E&gt; consumer) { ps.removeConsumer(consumer); }&lt;br /&gt;  boolean isFinished() { return ps.isFinished(); }&lt;br /&gt;&lt;br /&gt;  static interface Predicate&amp;lt;E&gt; {&lt;br /&gt;    boolean matches(E input);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And we're done.  Nowadays, the good news is that most IDEs will write delegate methods (like those above) automatically.&lt;br /&gt;&lt;br /&gt;To use Filter, one would write code like the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Filter&amp;lt;Foo&gt; filter = new Filter&amp;lt;Foo&gt;(&lt;br /&gt;  new Predicate&amp;lt;Foo&gt;() {&lt;br /&gt;    boolean matches(Foo input) {&lt;br /&gt;      return foo.name.equals("bob");&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;previousStage.addConsumer(filter);&lt;br /&gt;filter.addConsumer(nextStage);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, the Mongoose version.  I'll go through two iterations, the first closer to the Java version.&lt;br /&gt;&lt;br /&gt;A couple quick notes on this syntax:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;For generic types, the formal parameters and invocation type parameters are given in [square brackets].&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Type annotations are given in &amp;lt;angle brackets&amp;gt;.  They follow the argument or slot that they describe.  Methods may have an additional annotation describing the return type; if present, it follows the argument list and is separated by the return symbol ^.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If this reminds you of Strongtalk, you're a geek.&lt;br /&gt;&lt;br /&gt;Yes, there are two types of brackets in these definitions.  Square brackets surround blocks of code; curly brackets surround structural definitions.  This may seem annoying, but there's actually a good reason for this (which unfortunately doesn't come up in this example).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;protocol Producer[E] {&lt;br /&gt;  method addConsumer: consumer &amp;lt;Consumer[E]&gt;.&lt;br /&gt;  method removeConsumer: consumer &amp;lt;Consumer[E]&gt;.&lt;br /&gt;  method finished ^ &amp;lt;Boolean&gt;.&lt;br /&gt;}&lt;br /&gt;protocol Consumer[E] {&lt;br /&gt;  method consume: input &amp;lt;E&gt; from: source &amp;lt;Producer[E]&amp;gt;.&lt;br /&gt;  method producerFinished: producer &amp;lt;Producer[E]&amp;gt;.&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;No big difference here.  Moving along:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class ProducerSupport[E] {&lt;br /&gt;aspect class:&lt;br /&gt;  constructor for: owner [&lt;br /&gt;    _owner := owner.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;aspect instance:&lt;br /&gt;  implements Producer[E].&lt;br /&gt;&lt;br /&gt;  slot _owner &amp;lt;Producer[E]&gt;;&lt;br /&gt;    constant.&lt;br /&gt;  slot _consumers := Set[Consumer[E]] new;&lt;br /&gt;    constant.&lt;br /&gt;  slot _finished &amp;lt;Boolean&gt; := false.&lt;br /&gt;&lt;br /&gt;  method addConsumer: consumer &amp;lt;Consumer[E]&gt; [&lt;br /&gt;    _consumers include: consumer.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method removeConsumer: consumer &amp;lt;Consumer[E]&gt; [&lt;br /&gt;    _consumers remove: consumer.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method finished [ ^_finished ].&lt;br /&gt;&lt;br /&gt;  method emit: output &amp;lt;E&gt;;&lt;br /&gt;    private&lt;br /&gt;  [&lt;br /&gt;    _consumers each: [ :c | c consume: output from: owner ].&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method finish;&lt;br /&gt;    private&lt;br /&gt;  [&lt;br /&gt;    _finished := true.&lt;br /&gt;  ]&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The interesting bits, starting from the top:&lt;br /&gt;Behavior and state in Mongoose classes are separated into two &lt;em&gt;aspects&lt;/em&gt;, class and instance.  This is equivalent to the static/member divide in languages like Java or C++.  The main difference, in Mongoose, is that the two can actually be defined separately, though I haven't done that here.&lt;br /&gt;&lt;br /&gt;The method &lt;code&gt;#for:&lt;/code&gt; is implemented as a &lt;em&gt;constructor&lt;/em&gt;, which is analogous to Java and C++ again, but a bit more rigorously defined and flexible.  A constructor, in Mongoose, is a method that is invoked on a class, but executes on an object.  More importantly, a constructor is invoked like any other method on the class; callers don't know they're invoking a constructor, and you can change the implementation &amp;mdash; for example, to return a singleton instance, or delegate to another class &amp;mdash; without changing the callers.&lt;br /&gt;&lt;br /&gt;Notice that the &lt;code&gt;owner&lt;/code&gt; argument to &lt;code&gt;#for:&lt;/code&gt; lacks a type annotation.  This is an implementation shortcut; because the argument is being directly stuffed into the slot &lt;code&gt;_owner&lt;/code&gt;, which has a type annotation, the type can be inferred.  (Callers would see the type annotation when inspecting the class.)&lt;br /&gt;&lt;br /&gt;The rest is pretty simple.  The words &lt;code&gt;constant&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; following slot and method definitions (after the semicolon) are &lt;em&gt;attributes&lt;/em&gt;.  &lt;code&gt;constant&lt;/code&gt; says that a slot, once initialized, will never change; this also allows you to omit the type annotation.  As with final fields in Java, the slot must have an explicit initializer, or be set in a constructor.  &lt;code&gt;private&lt;/code&gt; says that a method is only available to other code within the class or subclasses thereof.&lt;br /&gt;&lt;br /&gt;Now, to Filter:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Filter[E] {&lt;br /&gt;aspect class:&lt;br /&gt;  constructor using: predicate &amp;lt;Block[E, Boolean]&gt; [&lt;br /&gt;    _predicate := predicate.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;aspect instance:&lt;br /&gt;  implements Producer[E] via _ps.&lt;br /&gt;  implements Consumer[E].&lt;br /&gt;&lt;br /&gt;  slot _ps := ProducerSupport[E] for: self;&lt;br /&gt;    constant.&lt;br /&gt;  slot _predicate &amp;lt;Block[E, Boolean]&gt;;&lt;br /&gt;    constant.&lt;br /&gt;&lt;br /&gt;  method consume: input &amp;lt;E&gt; from: source &amp;lt;Producer[E]&gt; [&lt;br /&gt;    (_predicate evaluate: input)&lt;br /&gt;      ifTrue: [ _ps emit: input ].&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method producerFinished: producer &amp;lt;Producer[E]&gt; [&lt;br /&gt;    _ps finish.&lt;br /&gt;  ]&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Most of this you've seen above; we have a basic constructor and some instance behavior and state.  However, a few points here merit further explanation.&lt;br /&gt;&lt;br /&gt;The constructor takes the &lt;em&gt;predicate&lt;/em&gt;, which performs the actual filtration.  It's typed as a Block, which is a standard Mongoose class describing a block of code (as in Smalltalk).&lt;br /&gt;&lt;br /&gt;Notice, in the instance aspect, that we're missing most of the code from the Java implementation.  The key is the second line in the aspect:&lt;br /&gt;&lt;code&gt;implements Producer[E] via _ps.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This is called a &lt;em&gt;via&lt;/em&gt;, and allows us to explicitly delegate all messages in the Producer protocol to another object &amp;mdash; in this case, the object in the slot &lt;code&gt;_ps&lt;/code&gt;.  Variations on vias allow you to delegate only a portion of a protocol, or a few named messages, but those aren't applicable here.&lt;br /&gt;&lt;br /&gt;In our case, the contents of &lt;code&gt;_ps&lt;/code&gt; are constant, but we might choose to switch out the object; any messages in the Producer protocol would automatically be forwarded to the new object.&lt;br /&gt;&lt;br /&gt;So, we've reimplemented the Java version without some tedious, boilerplate code.  How would we use such a class?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;filter := Filter[Foo] using: [ :foo | foo name = "bob" ].&lt;br /&gt;previousStage addConsumer: filter.&lt;br /&gt;filter addConsumer: nextStage.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Simply passing in a Block that performs our test is a lot simpler, not to mention more concise, than Java's anonymous class mechanism.&lt;br /&gt;&lt;br /&gt;So, we've eliminated a chunk of boilerplate code, and made the class easier to use.  However, we can do better.  Delegation is all well and good, but in this case, we're delegating to a single object that was specifically designed for delegation.&lt;br /&gt;&lt;br /&gt;This pattern smells like Java.  There's a better way to do this in Mongoose.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;strong&gt;trait&lt;/strong&gt; ProducerSupport[E] {&lt;br /&gt;  implements Producer[E].&lt;br /&gt;&lt;br /&gt;  slot _consumers := Set[Consumer[E]] new;&lt;br /&gt;    constant.&lt;br /&gt;  slot _finished &amp;lt;Boolean&gt; := false.&lt;br /&gt;&lt;br /&gt;  method addConsumer: consumer &amp;lt;Consumer[E]&gt; [&lt;br /&gt;    _consumers include: consumer.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method removeConsumer: consumer &amp;lt;Consumer[E]&gt; [&lt;br /&gt;    _consumers remove: consumer.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method finished [ ^_finished ].&lt;br /&gt;&lt;br /&gt;  method emit: output &amp;lt;E&gt;;&lt;br /&gt;    private&lt;br /&gt;  [&lt;br /&gt;    _consumers each: [ :c | c consume: output from: &lt;strong&gt;self&lt;/strong&gt; ].&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method finish;&lt;br /&gt;    private&lt;br /&gt;  [&lt;br /&gt;    _finished := true.&lt;br /&gt;  ]&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ProducerSupport, in Java, was designed as a reusable unit to provide Producer behavior through delegation.  Here, we've reimplemented ProducerSupport as a &lt;em&gt;trait&lt;/em&gt; &amp;mdash; a reusable chunk of state and behavior that classes can include.  The code in ProducerSupport will run within the class that includes it, so we've eliminated the concept of "owner" and the accompanying code &amp;mdash; now, the ProducerSupport &lt;em&gt;is&lt;/em&gt; the owner, and vice versa.&lt;br /&gt;&lt;br /&gt;Let's reimplement Filter using this new trait.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Filter[E] {&lt;br /&gt;aspect class:&lt;br /&gt;  constructor using: predicate &amp;lt;Block[E, Boolean]&gt; [&lt;br /&gt;    _predicate := predicate.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;aspect instance:&lt;br /&gt;  &lt;strong&gt;includes ProducerSupport[E].&lt;/strong&gt;&lt;br /&gt;  implements Consumer[E].&lt;br /&gt;&lt;br /&gt;  slot _predicate &amp;lt;Block[E, Boolean]&gt;;&lt;br /&gt;    constant.&lt;br /&gt;&lt;br /&gt;  method consume: input &amp;lt;E&gt; from: source &amp;lt;Producer[E]&gt; [&lt;br /&gt;    (_predicate evaluate: input)&lt;br /&gt;      ifTrue: [ &lt;strong&gt;self&lt;/strong&gt; emit: input ].&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  method producerFinished: producer &amp;lt;Producer[E]&gt; [&lt;br /&gt;    &lt;strong&gt;self&lt;/strong&gt; finish.&lt;br /&gt;  ]&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've highlighted the changes.  By including the ProducerSupport trait, we've automatically gained all its behavior &amp;mdash; so we no longer need to keep track of a ProducerSupport instance, or delegate using the via.  Filter also automatically implements the protocols exposed by its included traits &amp;mdash; in this case, Producer.&lt;br /&gt;&lt;br /&gt;Filter, at this point, has degenerated into a basic &lt;em&gt;Adapter&lt;/em&gt; pattern, converting the language's Block construct for use in the producer-consumer architecture.  The class is nearly trivial.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've tried to demonstrate the utility of the following Mongoose features:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Linguistic support for delegation through &lt;code&gt;via&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Blocks.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Traits.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;This new syntax is a work in progress; all the concepts described here work in my current Mongoose implementation, but the compiler is evolving as I work.  Any comments, suggestions, or questions are welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114879029995215787?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114879029995215787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114879029995215787' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114879029995215787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114879029995215787'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/05/mongoose-syntax-evolves-with.html' title='The Mongoose syntax evolves, with a comparison to Java'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114393905821317051</id><published>2006-04-01T16:40:00.000-08:00</published><updated>2006-04-01T17:41:38.590-08:00</updated><title type='text'>Resuming exceptions in Mongoose</title><content type='html'>Since the initial rev of Mongoose's Signal framework (the basis for its exception handling), exceptions have supported &lt;em&gt;resumption&lt;/em&gt;.  You can send the message &lt;code&gt;#resume&lt;/code&gt; to an exception and, if it supports resumption, execution will continue as though the exception had not been signaled.&lt;br /&gt;&lt;br /&gt;Generally, of course, this is a bad thing, and most exceptions don't support resumption.  There are a few that do, however; one of these is EncodingException.&lt;br /&gt;&lt;br /&gt;EncodingException is signaled by a CharacterDecoder object when it encounters invalid data in its input.  For example, the UTF8Decoder will signal an EncodingException if it encounters truncated, invalid, or overlong sequences in the input.&lt;br /&gt;&lt;br /&gt;CharacterDecoders agree (in their interface) that if the EncodingException is resumed, they will insert the Unicode replacement character (U+FFFD) in their output and attempt to continue decoding.&lt;br /&gt;&lt;br /&gt;So, let's look at two ways of handling a malformed UTF-8 byte sequence, taken from the UTF8Decoder test suite:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;| fragment |&lt;br /&gt;(-- Malformed sequence; the initial 0xC2 is missing a byte, and 0xA2 is spurious --)&lt;br /&gt;fragment := #( 0xC2, 0xC2, 0xA1, 0xA2, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21 ).&lt;br /&gt;&lt;br /&gt;UTF8Charset decode: fragment.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;This code will die with an EncodingException (with a message reading "Truncated form at 1").  Now, we want our decoder to be more tolerant, so let's have it gloss over these issues.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;| fragment |&lt;br /&gt;(-- Same byte sequence as before --)&lt;br /&gt;fragment := #( 0xC2, 0xC2, 0xA1, 0xA2, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21 ).&lt;br /&gt;&lt;br /&gt;| characters |&lt;br /&gt;[&lt;br /&gt;  characters := UTF8Charset decode: fragment.&lt;br /&gt;] on: EncodingException do: [ :ex |&lt;br /&gt;  (-- Replace invalid sequence with U+FFFD and attempt to continue. --)&lt;br /&gt;  ex resume.&lt;br /&gt;].&lt;br /&gt;&lt;br /&gt;characters do: [ :c |&lt;br /&gt;  Console writeCharacter: c.&lt;br /&gt;].&lt;br /&gt;Console writeCharacter: Character newline.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So, rather than dying, this fragment prints:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&amp;#xFFFD;&amp;iexcl;&amp;#xFFFD;Hello!&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;In an upcoming revision, you'll be able to provide a character or character sequence to use in place of invalid input, and have some control over overlong encodings specifically.&lt;br /&gt;&lt;br /&gt;(Readers might note some subtle syntax changes in the code fragments above.  The Mongoose syntax is evolving as we build out the standard libraries; stay tuned.)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; god, I love this language.  The enhancements are in place, in under a dozen lines of code.&lt;br /&gt;&lt;br /&gt;If you catch an EncodingException &lt;code&gt;ex&lt;/code&gt;, your options are as follows:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;ex resume&lt;/code&gt; will resume decoding.  If the exception was signaled due to an invalid byte sequence, it becomes the Unicode REPLACEMENT CHARACTER U+FFFD in the output.  If the exception was signaled due to an overlong encoding, it is decoded as if it were valid.  (This replicates the behavior of most (broken) UTF-8 decoders.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;ex resumeAndSkip&lt;/code&gt; will resume decoding; whatever input caused the exception will simply be ignored, and decoding will resume after it.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;ex resumeAndSubstitute: someCharacter&lt;/code&gt; does exactly what it sounds like: substitutes a character of your choosing for the invalid input.  So, to be like most Unix libraries, you can substitute &lt;code&gt;'?'&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114393905821317051?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114393905821317051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114393905821317051' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114393905821317051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114393905821317051'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/04/resuming-exceptions-in-mongoose.html' title='Resuming exceptions in Mongoose'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114292169769092116</id><published>2006-03-20T21:51:00.000-08:00</published><updated>2006-03-20T22:17:12.686-08:00</updated><title type='text'>Nutshell: my thoughts on static type checking</title><content type='html'>I've been giving a lot of thought to static type checking in Mongoose &amp;mdash; for three years now, in fact.&lt;br /&gt;&lt;br /&gt;Static type checking has a bad name these days, with programmers advocating fully dynamically-typed languages for productivity reasons, or to avoid complexity.&lt;br /&gt;&lt;br /&gt;I agree with the gist of the argument, but I feel it's based on bad data.  Here are my arguments.  (I'm not making the "static type systems allow for more optimizations" argument, since Self proved that one wrong 13 years ago.)&lt;br /&gt;&lt;br /&gt;&lt;em&gt;1. The popular static type systems are the worst examples.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Ask one of these programmers for an example of a static type system that holds them back.  I will virtually guarantee the answer is likely to be C, C#, C++, Java, Pascal, or Delphi.&lt;br /&gt;&lt;br /&gt;I will also virtually guarantee the answer is &lt;em&gt;not&lt;/em&gt; Ocaml, ML, or Haskell, three strongly-typed languages &amp;mdash; stronger even than the C family or Java, as they lack pointer aliasing, casts, and other ways to accidentally goof up your types at runtime.  And yet they don't get in the way (though the lack of operator overloading in ML is unfortunate).&lt;br /&gt;&lt;br /&gt;There are a number of reasons for this.  The ML family provides incredibly good type-inference support: the compiler looks at the operations you're performing on a value and where it came from, and deduces what type you wanted.  (In most interactive environments, it will report the types it deduces, so you can see if you screwed up.  Yes, the errors are yours, the compiler knows its stuff.)  As a result, the ML family (including Ocaml) doesn't require you to pedantically type every variable, like the C family.&lt;br /&gt;&lt;br /&gt;Microsoft added a sort of type-inference to C# in the latest version, but it only saves you from declaring your variable types &amp;mdash; instead of &lt;code&gt;int x&lt;/code&gt; you get to write &lt;code&gt;var x&lt;/code&gt;.  Woohoo.  Compared to ML, this is a toy feature, and it's a really bad fit for the language, in my uneducated country-boy opinion.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;2. Type declarations &amp;mdash; or type annotations, or whatever you want to call them &amp;mdash; are excellent documentation.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Maybe I'm just a bad programmer, but in Ruby, I find myself passing Strings when I really wanted to pass Integers &lt;em&gt;all the damn time&lt;/em&gt;.  The program usually doesn't die until runtime &amp;mdash; but it usually &lt;em&gt;does&lt;/em&gt; die, all because I forgot a &lt;code&gt;to_i&lt;/code&gt; somewhere in my parsing code.&lt;br /&gt;&lt;br /&gt;This is exacerbated by the fact that Strings, in Ruby, overload most arithmetic operators.  Rather than dying as soon as I try to add or shift a String, I just get a weird String.  (I do like it better than the transparent conversions in Perl, I'll say.)&lt;br /&gt;&lt;br /&gt;I have the same issues with Smalltalk.  Sometimes, it's just really nice to have documentation on what the expected type of a parameter is, what a function will return, or whether or not something can be null.  A lot of Smalltalk code fakes this, by naming the parameters after their expected type &amp;mdash; aSmallInteger, for instance.  This is really just an overgrown Hungarian notation, and violates one of my basic principles of software design: values should be named for their roles, not their types.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;3. Having a tool to check the accuracy of your documentation rocks.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;When writing Java in an IDE, I always leave Javadoc checking enabled.&lt;br /&gt;&lt;br /&gt;For those of you fortunate enough to have avoided Java, Javadoc-checking in an IDE verifies that your parameters are documented, their declared types are correct, and so forth &amp;mdash; in your comments.  It verifies that your comments are in sync with the source.  This is wonderful, since in Java, comments duplicate the information in the method signatures.  It keeps them from getting out of sync.&lt;br /&gt;&lt;br /&gt;Type declarations on parameters and results are a form of documentation &amp;mdash; and, in a static type system, they're checked by a tool called &lt;em&gt;the compiler&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;4. A sufficiently expressive static type system doesn't bind your hands.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;On this point, I must return &amp;mdash; as I so often do &amp;mdash; to Strongtalk.&lt;br /&gt;&lt;br /&gt;Strongtalk is a descendant of Smalltalk, a totally dynamic language.  One of the real powers of Smalltalk is its genericity: a parameter can be of any type at all, and as long as it responds to the set of messages you send it, your algorithm will work.  Pass it an integer, pass it a user-defined currency type, pass it a complex number &amp;mdash; it doesn't care, and neither do you.&lt;br /&gt;&lt;br /&gt;Strongtalk sports a static type system that preserves this power.  First, it's optional: if you honestly want a parameter to accept any type of object, that's fine.&lt;br /&gt;&lt;br /&gt;Second, it doesn't confuse "class" with "type."  Sure, you can say "this parameter must be a SmallInteger" &amp;mdash; but you can also say "this parameter must respond to this set of messages with these types"  In other words, you can describe the type in the same way that Smalltalk does (and Ruby does, and Python does, and...)  &amp;mdash; but in an explicit fashion, and one that the compiler can check for you!&lt;br /&gt;&lt;br /&gt;Strongtalk's type system is by far the most powerful and expressive that I've used.  It, single-handedly, convinced me that static typing was not a dead end &amp;mdash; but rather the path of least resistance.&lt;br /&gt;&lt;br /&gt;Something that Strongtalk, near as I can tell, &lt;em&gt;didn't do&lt;/em&gt; is infer the types and write the type declarations for you &amp;mdash; but there's really nothing preventing that.  This is one of the features I'm working into Mongoose, albeit slowly.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;5. Explicitness is good.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;I like explicit code.  (Yeah, I've worked for porn sites, but no jokes, please.)  I like explictness of intent, both on the part of the programmer, and on the part of third-party components.&lt;br /&gt;&lt;br /&gt;Static type systems are only one step in that direction.  Pre/postconditions and loop and class invariants are another.  (Really, type systems are a specific case of this, but I feel they're best expressed separately.)&lt;br /&gt;&lt;br /&gt;I'm in the very early stages of a contract-inference engine for Mongoose code, which will save the programmer the grunt work of writing pre/postconditions.  Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114292169769092116?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114292169769092116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114292169769092116' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114292169769092116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114292169769092116'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/nutshell-my-thoughts-on-static-type.html' title='Nutshell: my thoughts on static type checking'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114281513341892981</id><published>2006-03-19T16:26:00.000-08:00</published><updated>2006-03-19T16:38:53.430-08:00</updated><title type='text'>M2VM status report</title><content type='html'>M2VM is coming along.  It's proving as flexible as I'd hoped &amp;mdash; even changes to pretty fundamental structures, like the layout of an activation record, go off without a hitch.&lt;br /&gt;&lt;br /&gt;Hooray for metaprogramming, I say.&lt;br /&gt;&lt;br /&gt;Some notes:&lt;br /&gt;&lt;br /&gt;- My strict adherance to standard C (the GNU99 dialect, anyway, which I consider a standard) has kept portability simple.  The current codebase works great on all combinations of {Linux, Mac OS X} x { PPC32, PPC64, x86 }, without any architecture-specific defines or conditional compilation.  Of course, it also forces me to fight GCC's decisions in some areas, but I'm working on that.&lt;br /&gt;&lt;br /&gt;- Holy crap the Core Duos are fast.&lt;br /&gt;&lt;br /&gt;- Basically all of my development right now is in Mongoose; the C layer is mostly finalized, for now.  Even metaprogramming stuff like exception handling (which has to interact with the callstack), reflection, and dynamic loading is in Mongoose.  It's fun like Forth, but with better abstractions.&lt;br /&gt;&lt;br /&gt;- My Module abstraction seems to be good.  Modules contain classes and/or other modules, and serve as the largest granule of access control and scoping.  You can provide a filter when you load a Module, to prevent it from accessing, say, the reflection classes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The exception-handling facilities are coming along.  I've put together a brief (and possibly cryptic) &lt;a href="http://www.cliff.biffle.org/mongoose-exceptions.pdf"&gt;slide stack explaining the Mongoose exception mechanisms&lt;/a&gt; (244k PDF), explaining the various nuances.  (It supports Java-style unwind-and-abort handling, PL/1-style resumption, and a few other options.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114281513341892981?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114281513341892981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114281513341892981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114281513341892981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114281513341892981'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/m2vm-status-report.html' title='M2VM status report'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114239820895625434</id><published>2006-03-14T20:46:00.000-08:00</published><updated>2006-03-19T01:18:47.356-08:00</updated><title type='text'>Indirect threading is...slower?</title><content type='html'>Well, that was unexpected.&lt;br /&gt;&lt;br /&gt;M2VM so far has been using the switched-interpreter mode of my VM generator.&lt;br /&gt;&lt;br /&gt;As of yesterday, my profiler no longer says the GC is the bottleneck &amp;mdash; now, it's the interpreter loop.  So, logically, I've started to optimize it.&lt;br /&gt;&lt;br /&gt;As a first step, I switched the VM generator to produce indirect-threaded code &amp;mdash; simply looking up the address of each bytecode's code, using an array of addresses (one for each bytecode).  I expected this to be faster.&lt;br /&gt;&lt;br /&gt;It's about 10% slower on my benchmarks.  (It's about the same speed at -O1, but at higher levels it gets slower and slower.)&lt;br /&gt;&lt;br /&gt;I'll drill down with some profiling to see if I can find the cause, but this kinda blows my mind.  The generated code for the switch statement was the hottest in the module, so I assumed that, by getting it out of the way, things would speed up.&lt;br /&gt;&lt;br /&gt;Hrm.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; This is only true on the G4/G5.  On an Intel Core Duo system, the indirect threaded interpreter is an instant 10% speed &lt;em&gt;boost&lt;/em&gt;.  However, I've found an issue with GCC's code generation that's ruining my indirect branch prediction rate &amp;mdash; which may explain the issues on the G5.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114239820895625434?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114239820895625434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114239820895625434' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114239820895625434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114239820895625434'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/indirect-threading-isslower.html' title='Indirect threading is...slower?'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114232381024862873</id><published>2006-03-13T23:45:00.000-08:00</published><updated>2006-03-14T00:10:10.263-08:00</updated><title type='text'>Politeness</title><content type='html'>I've been thinking more about the Politeness Principle I mentioned in the last entry, and I think it's pretty descriptive.  In this post, I'll illustrate it with an extended metaphor: food service.&lt;br /&gt;&lt;br /&gt;First, let's start with a procedural/imperative food service.&lt;br /&gt;&lt;br /&gt;Assume for the moment that, in some sort of bizzare Zamyatin fantasy, everyone is identical.  The food service folks come to your little cubicle three times a day and stuff food down your throat.  You have no say in how much or what you're fed &amp;mdash; it is literally stuffed down your throat.&lt;br /&gt;&lt;br /&gt;This, as I think we all can agree, is the least polite level of foodservice.  It's also basically how most imperative programming styles work: a single process is in control (the program) and it directly modifies data.&lt;br /&gt;&lt;br /&gt;Everyone doesn't have to be exactly the same; there can be some variation, as long as it's evident to the program.  When people arrive at work, they could receive a colored card, stuck to their forehead, indicating the type of eater they are.  A red card, say, might indicate lots of food, while a blue card indicates less food.  The food service folks come by, look at the card, and stuff food down your throat.&lt;br /&gt;&lt;br /&gt;Now, say you want an amount of food in between the two extremes &amp;mdash; or say you're fasting or not hungry that day.  You stick a purple card to your forehead.&lt;br /&gt;&lt;br /&gt;The food service folks come by, look at your card, and have no well-defined response.  If you're lucky, they might get confused and move on to the next person &amp;mdash; if you're unlucky, they might stuff &lt;em&gt;all&lt;/em&gt; the food down your throat, or remove you from your cube and replace you with a human-shaped stack of mashed potatoes.  The foodservice person might even commit ritual suicide at your feet.  The behavior, either way, is undefined.  In programming, this is called a "tagged type" &amp;mdash; it has a tag indicating how it should be dealt with.  As in foodservice, a program must be warned of all the possible tags in advance, or undefined (read: usually bad) things may result.  Generally this is either lost data, or corrupted data (replaced with mashed potatoes) &amp;mdash; or a program crash.&lt;br /&gt;&lt;br /&gt;So, we define some new tags for new types of eaters.  Say, green for vegetarian, black for fasting, white for no-gluten.  Then we need a new color for vegetarian-heavy-eater, no-gluten-heavy-eater, etc. &amp;mdash; every combination we want to handle.  This will quickly spiral out of control, with the foodservice people needing to carry tomes explaining what to do in any given case.  The foodservice job has gotten very complex, because the people are treated as dumb: they are given a tag, and that's the only communication.&lt;br /&gt;&lt;br /&gt;At this point, some bright young foodservice luminary might suggest a revolutionary idea: "Why don't we ask the people?"  This is basically the paradigm shift that Smalltalk brought to programming: don't put all the intelligence in the process, let the data itself be intelligent.  But a first crack at this is almost always wrong.&lt;br /&gt;&lt;br /&gt;The foodservice worker arrives at your cube one morning and, without even looking at your tag, says "Would you like one or two helpings of meat?"  "Oh, no thanks," you say, and the foodservice worker shoves one helping down your throat.  (The vegetarian next door is even less happy about this.)  The question was wrong, and you gave an unexpected answer.  This is usually what procedural programmers do when let loose in an object-oriented language like Smalltalk: they let the data be intelligent in all the wrong ways.&lt;br /&gt;&lt;br /&gt;It's still not very polite.  You're not given freedom of choice, and you certainly don't get to eat at your own pace.  Sure, you get to answer a question now, but your eating is still being micromanaged.&lt;br /&gt;&lt;br /&gt;As a next crack, the foodservice fellow says "Pick one of the items from this list."  If one of them suits you, great, and he shoves it down your throat.  If none of them are appropriate, well, too bad, you don't get to eat.&lt;br /&gt;&lt;br /&gt;A lot of software systems are half-polite.  By analogy, the fellow would roll up a buffet of eats, with some prepared dishes and some raw ingredients, perhaps with a small array of cooking utensils.  He would wait patiently while you prepared a dish to perfectly suit your liking, or allow you to refuse if you weren't hungry.&lt;br /&gt;&lt;br /&gt;And then he would shove it down your throat.&lt;br /&gt;&lt;br /&gt;In a slightly more refined system, he would wait until you had prepared the dish, and then move your arm to the fork and guide it into your  mouth for each bite.  If he were really nice, he would watch for cues (bloating, vomiting) and stop feeding you, but don't count on it.&lt;br /&gt;&lt;br /&gt;All this throat-shoving and force-feeding is starting to make you feel a wee bit violated, and that's exactly the term used in software: specifically, this is "violation of encapsulation."  Your eating procedures &amp;mdash; and, for that matter, your gastrointestinal tract &amp;mdash; are your business, and are &lt;em&gt;encapsulated&lt;/em&gt; away from the foodservice procedures.&lt;br /&gt;&lt;br /&gt;This allows each eater to have variations.  Some folks eat slower; some folks (the author included) tend to just tilt the plate back and let the entire meal plummet to its digestive doom.  Just as a polite procedure lets you pick and choose your own ingredients, a &lt;em&gt;really&lt;/em&gt; polite procedure would &lt;em&gt;just let you freakin' eat.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;So, ideally, the buffet would wait as you consumed your meal (or didn't) at your own pace, let you take another helping if required, and then bid you adieu.  This would be polite.&lt;br /&gt;&lt;br /&gt;The essence of the principle is this:&lt;br /&gt;1. Don't micromanage.&lt;br /&gt;2. Don't poke around in peoples' privates.  &lt;br /&gt;3. The easiest way to allow individual variation is to let people do things for themselves.&lt;br /&gt;&lt;br /&gt;This can be applied to software design, as I'm doing with Mongoose, by replacing "people" with "software components."  In the LinkedList I described in a previous post, I noted that the program doesn't forcefully grab some elements of the list and do actions on them; the process is closer to "Hey, element &lt;em&gt;x&lt;/em&gt;, do this, and ask your neighbors to do it too."&lt;br /&gt;&lt;br /&gt;As for individual variation, I dropped in an alternative Link implementation, RunLink, that can represent multiple identical elements with a single node.  It required &lt;em&gt;no changes to LinkedList&lt;/em&gt;, because LinkedList didn't care about the internals of the links &amp;mdash; it only sent them messages and worked with their responses.&lt;br /&gt;&lt;br /&gt;This is the real power of object-oriented design, and unfortunately it's lost on a lot of folks working in OO.  I think it's that they haven't had it explained well.  This blog post is off the top of my head, so it continues to be explained poorly, but you get the idea, I hope.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114232381024862873?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114232381024862873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114232381024862873' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114232381024862873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114232381024862873'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/politeness.html' title='Politeness'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114221398901504123</id><published>2006-03-12T17:18:00.000-08:00</published><updated>2006-03-12T18:36:05.606-08:00</updated><title type='text'>Tail recursion, micromanagement, and naughty bits</title><content type='html'>On this fine Sunday afternoon, I've been assembling a LinkedList class for the Mongoose standard library (in the Collections module).  It's a pretty standard doubly-linked list &amp;mdash; a freshman-level chore that I've done in at least a dozen languages through the years.  Recently, good high-level languages have saved me the work by bundling an implementation &amp;mdash; but when you create your own language, the giants' shoulders are smaller and less comfortable.&lt;br /&gt;&lt;br /&gt;So, let's take the task of getting a particular link within the list.  (A Link is an object that knows who its neighbors are, and holds a reference to some value.)  Once you can get a link, you can get its value, or navigate around it.&lt;br /&gt;&lt;br /&gt;In C, Java, and other procedural languages, you would probably do this with a loop and at least one scratch variable.  Loops and scratch variables smell funny to me.&lt;br /&gt;&lt;br /&gt;Mongoose calls this method &lt;code&gt;linkAt:&lt;/code&gt;, and it's implemented like this:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;(-- ... in LinkedList ... --)&lt;br /&gt;@method self linkAt: index [&lt;br /&gt;  (_count = 0) ifTrue: [ ^nil ]. (-- no links to return? --)&lt;br /&gt;  ^_head seekForwardBy: index.&lt;br /&gt;].&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;It checks if the list contains no elements (as indicated by an instance slot named &lt;code&gt;_count&lt;/code&gt;), and returns &lt;code&gt;nil&lt;/code&gt; if this is so.  Otherwise, it tells the head of the list (a Link named &lt;code&gt;_head&lt;/code&gt;) to peek ahead some number of elements and return the neighbor it finds.&lt;br /&gt;&lt;br /&gt;Of course, &lt;code&gt;_head&lt;/code&gt;, like other Links, only knows its immediate neighbors, so it delegates.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;(-- ... in Link ... --)&lt;br /&gt;@method self seekForwardBy: offset [&lt;br /&gt;  (offset = 0) ifTrue: [ ^self ]. (-- that's me! --)&lt;br /&gt;  ^_next seekForwardBy: offset - 1.&lt;br /&gt;].&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;It checks if the &lt;code&gt;offset&lt;/code&gt; is zero, and if so, doesn't do any work at all: it simply returns itself.  Otherwise, it pawns the work off on its next neighbor (named, appropriately, &lt;code&gt;_next&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;When I wrote this code (with the exception of a couple poor name choices), it just &lt;em&gt;felt good&lt;/em&gt;, and I wanted to know why.  I think it comes down to one thing:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;There is no micromanagement.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;In a normal LinkedList implementation (and, I admit, in the first draft of my Mongoose class), the list itself examines each Link, checking who its neighbors are.  It controls the navigation; it interrogates every Link, leaving it feeling confused and violated.&lt;br /&gt;&lt;br /&gt;This implementation does nothing of the sort: it asks the Link to find out a bit of data.  Each Link can then ask its neighbors as appropriate.  It comes back to one of the principles espoused by Smalltalk, which I refer to as the Politeness Principle: &lt;em&gt;don't micromanage&lt;/em&gt;, or, alternatively, &lt;em&gt;ask objects to do things; don't peek at their naughty bits and decide for them.&lt;/em&gt;  (On that note, it could be considered the gender equality principle as well.)&lt;br /&gt;&lt;br /&gt;As I iteratively refactored LinkedList to make it Polite, I tried to improve politeness while still using a traditional while-loop, thinking it would be more readable for most programmers.&lt;br /&gt;&lt;br /&gt;I failed.&lt;br /&gt;&lt;br /&gt;Which brings me to my next thought on the matter: tail calls are really the only Polite way to do iteration.  There's no one object or routine managing the process; instead, each stage successively asks the next, "Do whatever you think we should with this data," and it can decide whether or not to continue.&lt;br /&gt;&lt;br /&gt;Mongoose has optimized tail calls since M1 as its fundamental iteration primitive, but I didn't add them because they were Polite &amp;mdash; I added them because they were less conceptually nasty than a &lt;code&gt;goto&lt;/code&gt;, which is how most other languages iterate.&lt;br /&gt;&lt;br /&gt;On the other hand, Smalltalk, the origin of the Politeness Principle, &lt;em&gt;does not mandate tail-call optimization&lt;/em&gt;.  In my tests on some current Smalltalks, it doesn't seem common.  This blows my mind: it's only proper!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; I had misstated the Politeness Principle; I'm looking for a concise yet correct definition now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114221398901504123?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114221398901504123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114221398901504123' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114221398901504123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114221398901504123'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/tail-recursion-micromanagement-and.html' title='Tail recursion, micromanagement, and naughty bits'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114216286883736160</id><published>2006-03-12T03:22:00.000-08:00</published><updated>2006-03-12T03:27:48.853-08:00</updated><title type='text'>Runtime type information and exception handling</title><content type='html'>The design of Mongoose includes a number of 'little experiments.'&lt;br /&gt;&lt;br /&gt;For example, Mongoose doesn't provide a standard way to determine an object's class.  This is on purpose; the class of an object is an implementation detail.  You can use the reflection API to find out if you really need to know, but chances are, you don't.  Instead, you can check an object for conformance to a certain protocol (a set of messages), and the object may very well change its conformance at runtime.&lt;br /&gt;&lt;br /&gt;I've managed to implement most of the Mongoose standard library in this fashion, but I've hit a bit of a roadblock: structured exception handling.&lt;br /&gt;&lt;br /&gt;Specifically, it's really nice to be able to define a number of exception handlers, specialized on the type of exception encountered.  The traditional way to do this in languages like Java is to specialize on the exception's class.&lt;br /&gt;&lt;br /&gt;Sure, I could do this other ways &amp;mdash; say, check some 'exception type' parameter &amp;mdash; but it feels like a workaround, and requires another layer of namespace to avoid collisions.&lt;br /&gt;&lt;br /&gt;This will require some thought.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114216286883736160?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114216286883736160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114216286883736160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114216286883736160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114216286883736160'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/runtime-type-information-and-exception.html' title='Runtime type information and exception handling'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114179608721605865</id><published>2006-03-07T21:16:00.000-08:00</published><updated>2006-03-08T22:50:33.810-08:00</updated><title type='text'>Mongoose syntax</title><content type='html'>As a brief followup to my last post, here's the entire Mongoose language syntax.  It's not in a single paragraph for clarity, but it's still quite concise.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Literals&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Strings are enclosed in double-quotes.  Any double-quotes within the string are escaped with backslash.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Characters are enclosed in single-quotes.  A single-quote must be escaped.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integers can be base 10 (42), base 16 (0x2A), or base 2 (0b101010).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Symbols (used to name messages) begin with a hash mark (#) and can contain any legal message (see below).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Arrays can contain any sequence of expressions, contained in #( ... ).&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;A normal set of control characters can be used in strings and characters using backslash (\n, \t, \e, etc.), plus Unicode hex escapes (\u002A).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Sending Messages&lt;/h2&gt;&lt;br /&gt;All messages are sent to a receiver.  There are three types of message sends: unary, binary (operator), and keyword.&lt;br /&gt;&lt;code&gt;receiver unaryMessage&lt;/code&gt; sends #unaryMessage to &lt;code&gt;receiver&lt;/code&gt;.&lt;br /&gt;&lt;code&gt;receiver + argument&lt;/code&gt; sends #+ to &lt;code&gt;receiver&lt;/code&gt; with an argument (where + can be any sequence of Unicode operator characters)&lt;br /&gt;&lt;code&gt;receiver do: this with: that&lt;/code&gt; sends #do:with: to &lt;code&gt;receiver&lt;/code&gt; (where &lt;code&gt;this&lt;/code&gt; and &lt;code&gt;that&lt;/code&gt; are arguments)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Precedence&lt;/h2&gt;&lt;br /&gt;Unary-&amp;gt;Binary-&amp;gt;Keyword.&lt;br /&gt;Thus,&lt;br /&gt;&lt;code&gt;4 squared + 2 to: 12 + 8 factorial&lt;/code&gt;&lt;br /&gt;is equivalent to&lt;br /&gt;&lt;code&gt;((4 squared) + 2) to: (12 + (8 factorial))&lt;/code&gt;&lt;br /&gt;All operators have equal precedence.&lt;br /&gt;Precedence can be overridden using parentheses.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Statements&lt;/h2&gt;&lt;br /&gt;A statement takes one of three forms: normal, assignment, and return.&lt;br /&gt;A normal statement is simply a message send (which can have message sends as its receiver or arguments, recursively).&lt;br /&gt;An assignment statement consists of a variable, the assignment symbol :=, and a message send, like&lt;br /&gt;&lt;code&gt;foo := bar value.&lt;/code&gt;&lt;br /&gt;A return statement consists of the return symbol ^, and a message send, like&lt;br /&gt;&lt;code&gt;^bar value.&lt;/code&gt;&lt;br /&gt;Statements are separated by a full stop.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Declaring Variables&lt;/h2&gt;&lt;br /&gt;Local variables are declared between vertical bars, like this:&lt;br /&gt;| x |&lt;br /&gt;| x. y. z. |&lt;br /&gt;Thanks to a wee bit of context-sensitivity in the parser, | is still available as an operator.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Identifiers&lt;/h2&gt;&lt;br /&gt;Any non-whitespace, non-punctuation Unicode character (plus the underscore) is legal in an identifier.  Identifiers must not start with a digit.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Blocks&lt;/h2&gt;&lt;br /&gt;A block is a set of statements enclosed in square brackets ( [ ... ] ).  Blocks may contain any mix of statements and variable declarations.  A block can define arguments, which must appear in a declaration at the start of the block; arguments are indicated with colons, eg&lt;br /&gt;&lt;code&gt;[ | :x | x + 2]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Scoping&lt;/h2&gt;&lt;br /&gt;Scoping is entirely lexical.  There are no global variables.  Specifically, scopes at this point nest as follows:&lt;br /&gt;class variables -&amp;gt; method arguments -&amp;gt; method locals &amp;gt; block arguments/locals (-&amp;gt; block arguments/locals...)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Reserved Words&lt;/h2&gt;&lt;br /&gt;Mongoose has three reserved words.  &lt;code&gt;self&lt;/code&gt; refers to the object whose method is currently executing.  &lt;code&gt;super&lt;/code&gt; is an alias for &lt;code&gt;self&lt;/code&gt; that starts method lookup at the parent class.  &lt;code&gt;Self&lt;/code&gt; (capitalized, like a class) is a placeholder for the class of &lt;code&gt;self&lt;/code&gt;, whatever it may be (in descendants and the like).&lt;br /&gt;&lt;br /&gt;&lt;code&gt;self&lt;/code&gt; is not a reserved word per se; it can be bound to any identifier within a method, but the compiler currently enforces &lt;code&gt;self&lt;/code&gt;.  &lt;code&gt;Self&lt;/code&gt; (capitalized)  is likely to be renamed, due to the potential for confusion with &lt;code&gt;self&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I'm considering a couple additional literal forms, but that's the entire language at the moment.&lt;br /&gt;&lt;br /&gt;For writing classes in text format, there's a declarative format that lays out methods and such, but it's extrasyntactic right now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114179608721605865?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114179608721605865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114179608721605865' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114179608721605865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114179608721605865'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/mongoose-syntax.html' title='Mongoose syntax'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114179486144310369</id><published>2006-03-07T21:05:00.000-08:00</published><updated>2006-03-07T21:15:31.190-08:00</updated><title type='text'>On Unicode.</title><content type='html'>I'm a big fan of Unicode.&lt;br /&gt;&lt;br /&gt;Well, not Unicode &lt;em&gt;specifically&lt;/em&gt;, but character sets that aren't annoyingly limited.  Watching software at my last job fumble around with accented characters &amp;mdash; much less Kanji &amp;mdash; really clubbed this into my head.&lt;br /&gt;&lt;br /&gt;Mongoose, since M1 in 2004, has supported Unicode throughout.  I'm continuing this in the M2 implementation.&lt;br /&gt;&lt;br /&gt;Mostly, it's for clarity.  I consider &amp;ne; to be a lot clearer than != or /= or .ne. or whatever other hacks other languages have used.  Same with &amp;le; and the like.  As of tonight, the current compiler and runtime support all this &amp;mdash; Object understands the &amp;ne; message and does the right thing, and so on.  Unicode handles such characters quite well: there's a reserved block (U+2200 through U+22FF) for operators.  Any of these characters are now legal Mongoose operators, from the compiler on up.&lt;br /&gt;&lt;br /&gt;This gets a lot of grumbling from the old guard, but I'm not really open to grumbling on such matters.  Any Mac user can type all these symbols directly from their keyboards, without having to enter hex codes or some nonsense.  I've included message synonyms for the keyboard-impaired (!=, &lt;=, etc.), but they're just that: synonyms for the real message.&lt;br /&gt;&lt;br /&gt;I've been thinking, over the past few years, about ALGOL syntax.  ALGOL originally defined a 'pretty' syntax &amp;mdash; the print syntax, iirc &amp;mdash; that used subscripts for array access and the like.  This was well outside the capability of machines at the time, of course, so the syntax that lived on in its descendants used A[2] instead of A&lt;sub&gt;2&lt;/sub&gt;.&lt;br /&gt;&lt;br /&gt;I think we're getting to the point where such print syntaxes could be made official.  A List might use any subscripted expression as an element accessor; a Number might use a superscripted expression as an exponent.  As long as it's easy to enter (which, right now, it's not), I think this could be a win.&lt;br /&gt;&lt;br /&gt;But that's because I'm insane.&lt;br /&gt;&lt;br /&gt;Mongoose is unlikely to support any such thing, since it's the dreaded "orthogonal syntax feature" I'm avoiding.  I like that the entire language syntax can be described in a paragraph, including every possible way a method might be invoked.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114179486144310369?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114179486144310369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114179486144310369' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114179486144310369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114179486144310369'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/on-unicode.html' title='On Unicode.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114127955873556759</id><published>2006-03-01T21:57:00.000-08:00</published><updated>2006-03-01T22:05:58.753-08:00</updated><title type='text'>Reinventing the wheel!</title><content type='html'>I never thought I'd say this, but I kinda wish I were writing in C++.&lt;br /&gt;&lt;br /&gt;Seriously.  As I write my own hashmap implementation in C, I'm wishing I had access to the STL.  Fortunately, this is for the bootstrap loader in M2VM, so it only needs to index the bootstrap classes.  There are 14 (see footnote), so if I take a shortcut and make lookups O(n), nothing will catch fire.&lt;br /&gt;&lt;br /&gt;M1 avoided this whole issue by hardcoding the bootstrap classes, creating them directly from the C code.  This is rather icky and makes development a pain.  It's also silly in terms of M2VM, since none of these classes have any distinguished role from the VM's perspective.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Footnote: to start the userspace classloader, written in Mongoose, the M2VM needs the following classes: Object, Class, Nil, Boolean, True, False, SmallInteger, Character, String, Method, Array, ByteArray, MethodContext, and BlockContext.  Character is technically optional, but I'm including it to ensure that Strings are fully functional.  Object is also technically optional, as Mongoose has no distinguished root class, but it makes the class graph complete.&lt;br /&gt;&lt;br /&gt;Unlike most Smalltalk-derived VMs, the Symbol class &amp;mdash; which represents unique, &lt;em&gt;intern&lt;/em&gt;ed Strings, for message sends and the like &amp;mdash; is not distinguished.  It's implemented entirely in userspace using a pretty standard GoF flyweight pattern.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114127955873556759?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114127955873556759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114127955873556759' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114127955873556759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114127955873556759'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/03/reinventing-wheel.html' title='Reinventing the wheel!'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114101093345209526</id><published>2006-02-26T19:13:00.000-08:00</published><updated>2006-02-26T19:29:26.506-08:00</updated><title type='text'>Excellent GC papers</title><content type='html'>As some of my past blog entries have implied, I dislike needlessly long, convaluted CS papers.&lt;br /&gt;&lt;br /&gt;Now, my experience in formal writing is primarily in psychology, and I know that APA style dictates a certain wordiness &amp;mdash; extensive citations of prior related work, etc.  At ASU, at least, APA papers were actually prohibited from using quotations, so any referenced material had to be restated or paraphrased.  So, I imagine some of the wordiness in CS papers is purely stylistic.&lt;br /&gt;&lt;br /&gt;However, every so often I find really to-the-point papers.&lt;br /&gt;&lt;br /&gt;My favorite example is &lt;a href="http://www.cs.ucsb.edu/~urs/oocsb/papers/write-barrier.pdf"&gt;H&amp;ouml;lzle's 1993 paper on write barriers in Self&lt;/a&gt;.  I came across this a couple years ago, when I was studying Self.  It explains its purpose, summarizes prior work (including concise code snippets), and presents its results in just 6 pages &amp;mdash; and the idea it's presenting is non-trivial.  Marvelous.  (Dr. H&amp;ouml;lzle is not in my line of direct supervisors at work, either, so this isn't brown-nosing.)&lt;br /&gt;&lt;br /&gt;I'm currently reading &lt;a href="http://www.aicas.com/papers/cc01_fsiebert.pdf"&gt;a 2001 paper by Fridtjof Siebert discussing root scanning in garbage collectors&lt;/a&gt;.  It's also delightfully punchy, at 15 pages.  I came across it during my research today, and it made me both happy and sad.&lt;br /&gt;&lt;br /&gt;Happy, because it lays out (rather more formally) some of the techniques I'm using in M2VM's collector.  (Because of M2VM's Smalltalk origins, &lt;em&gt;all&lt;/em&gt; trace roots are in heap at well-defined points during execution.)&lt;br /&gt;&lt;br /&gt;Sad, because I thought I was all cool for coming up with this idea.  According to the paper, I'm at $StateOfTheArt - 4 years. :-)&lt;br /&gt;&lt;br /&gt;The good news: Siebert's scheme is tailored to uniprocessor systems, where having a single active thread is acceptable &amp;mdash; whereas my variation is explicitly designed for multiprocessor machines (like mine).  I'm sure this leap has already been made in the literature, but it's nice to know I'm not entirely insane.&lt;br /&gt;&lt;br /&gt;For any interested parties: my approach has threads check a global condition variable at certain synchronization points.  If any thread would like a collection to occur, it sets the variable and waits for other threads to reach a synchronization point; each thread flushes registers to heap and decrements a countdown semaphore when they reach synchronize.  Once all threads have synchronized, the collector traces the roots and marks reachable objects, and all threads resume while the collection completes.&lt;br /&gt;&lt;br /&gt;Because each thread's context information is accessible through a reference in global scope (actually from a pthread TLS slot), finding and tracing the roots is O(n) for n threads.  (The full trace phase is still linear for the number of reachable objects, as usual.)&lt;br /&gt;&lt;br /&gt;I'm looking at a couple enhancements for parallel tracing and scavenging, and trying to find a good way to apply this to full collections (currently, it's limited to minor, new-gen collections).  We'll see.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114101093345209526?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114101093345209526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114101093345209526' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114101093345209526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114101093345209526'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/excellent-gc-papers.html' title='Excellent GC papers'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114095090856483439</id><published>2006-02-26T02:23:00.000-08:00</published><updated>2006-02-26T16:12:03.813-08:00</updated><title type='text'>Developer: 1; Garbage Collector: 0</title><content type='html'>Garbage collector bugs are some of the hardest I've ever debugged (with the possible exception of massive concurrency or distributed systems).  "Y'know that memory address you were just PEEKing at?  Yeah, it moved.  See if you can find it now, sucker."&lt;br /&gt;&lt;br /&gt;However, I've beaten this one, and the M2VM garbage collector is working again.  Found a number of oversights in my implementation; I knew the initial mark-compact collector was a stopgap measure, and boy, did I write it like a stopgap measure. :-)&lt;br /&gt;&lt;br /&gt;I've also gained a real appreciation for gdb.  At some point in the last few years, it's learned to reload single functions from a modified binary on the fly, as well as dynamically reloading and relinking shared libraries.  I can switch windows, recompile my GC, rebind the entry point, and resume execution.  Pretty sweet.  (These might be Apple-specific enhancements, not sure.)&lt;br /&gt;&lt;br /&gt;So, the GC is creeping right along &amp;mdash; emphasis on the &lt;em&gt;creeping&lt;/em&gt;.  Like any na&amp;iuml;ve mark-compact collector, it causes nasty pauses &amp;mdash; as much as 1s on a 40MB heap.  Hand it a heavily fragmented 1GB heap, and not even my 2.5GHz G5 can make the experience pleasant.&lt;br /&gt;&lt;br /&gt;I've found some creative ways to optimize it, but it raises the question of how much to tune throwaway code.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; corrected "mark-sweep" to say "mark-compact."  I had actually forgotten that non-moving tracing collectors existed.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; in answer to my final question, I modified the mark-compact collector to use a simple generational strategy.  Work required: 2 lines of code.  Speedup: 100x.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114095090856483439?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114095090856483439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114095090856483439' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114095090856483439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114095090856483439'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/developer-1-garbage-collector-0.html' title='Developer: 1; Garbage Collector: 0'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114090466256863322</id><published>2006-02-25T13:54:00.000-08:00</published><updated>2006-02-25T13:57:42.583-08:00</updated><title type='text'>Night and Day</title><content type='html'>&lt;a href="http://notgartner.com/posts/3722.aspx"&gt;The Day Programmer vs. The Night Programmer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are those who program to make money, and there are those who program because it captivates them.  This is a point I've come across many times through the years, but this fellow elucidates it particularly well.&lt;br /&gt;&lt;br /&gt;My interviewing style, for example, is specifically designed to weed out the former type.  (Which, I suspect, is why I didn't do more interviews at Choice.  They were frightened and confused by the latter type.)&lt;br /&gt;&lt;br /&gt;Not sure which I am.  *goes back to spending Saturday tuning his virtual machine*&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114090466256863322?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114090466256863322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114090466256863322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114090466256863322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114090466256863322'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/night-and-day.html' title='Night and Day'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114067548427681075</id><published>2006-02-22T22:09:00.000-08:00</published><updated>2006-02-22T22:19:29.186-08:00</updated><title type='text'>IT'S ALIIIIIVE!</title><content type='html'>Since Saturday, I've been hacking on M2VM, my next-generation Mongoose VM.  It uses the VM-generation utility I described in my last post.&lt;br /&gt;&lt;br /&gt;As of tonight, it works.  I have:&lt;br /&gt;&lt;br /&gt;1. Designed a class-file format, similar to Java's but better suited.  (This is a stopgap measure; M2VM will load classes a module-at-a-time using a yet-to-be-defined format based on the class-file format.)&lt;br /&gt;2. Written a set of utilities (in Java) for building up M2VM code, in preparation for a compiler.  (At this point, it generates class files from a tree-based IR, so the compiler layer will be very thin and probably entirely ANTLR.)&lt;br /&gt;3. Written the VM generator (in Ruby) that transforms 151 lines of very manageable domain-specific code into 334 lines of VM inner loop.&lt;br /&gt;4. Written a rudimentary memory manager and garbage collector (in C) with the fundamentals of my eventual zone-based scheme.&lt;br /&gt;5. Written a stopgap class loader (in C) that works with the object memory API to build classes in RAM.&lt;br /&gt;6. Written a test framework that creates objects and sends messages to them.&lt;br /&gt;&lt;br /&gt;So, having fed it the equivalent (in pseudocode) of:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;sample() {&lt;br /&gt;   return self.&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;...I now get a correct return value!&lt;br /&gt;&lt;br /&gt;Nested and recursive calls also work.&lt;br /&gt;&lt;br /&gt;I'm using my generator in &lt;code&gt;switch&lt;/code&gt;ed mode, so I need to kick it into direct-threading and test that.  (It works for some limited test input, and most of the code is boilerplate in the Ruby.)  I also need to test some fundamentals &amp;mdash; argument passing comes to mind &amp;mdash; and flesh out some error handling, but...&lt;br /&gt;&lt;br /&gt;... it works!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114067548427681075?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114067548427681075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114067548427681075' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114067548427681075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114067548427681075'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/its-aliiiiive.html' title='IT&apos;S ALIIIIIVE!'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-114034893333322346</id><published>2006-02-19T03:04:00.000-08:00</published><updated>2006-02-19T03:37:52.586-08:00</updated><title type='text'>Virtual machine generators are a fun way to spend Saturday night!</title><content type='html'>Last night, I started work on a new version of the Mongoose VM.  The previous implementation (M1) was a testbed for a bunch of competing ideas, many of questionable value &amp;mdash; so the code was pretty hairy.&lt;br /&gt;&lt;br /&gt;The new implementation (M2) uses a simplified bytecode, has a Java-like classfile format for separate compilation (M1 was image-based), and is starting life as a coalescing threaded interpreter.&lt;br /&gt;&lt;br /&gt;Once I'd made it a bit into the implementation, I realized how much boilerplate code was involved in writing a VM.  So, I assembled some tools (in Ruby, of all languages) to help me out.  I now have a domain-specific language for describing VMs, which includes&lt;br /&gt;- Describing the logical register set;&lt;br /&gt;- Describing bytecode functions and formats;&lt;br /&gt;- Providing C implementations for operations;&lt;br /&gt;- Describing the calling conventions for invoking the VM itself from C code.&lt;br /&gt;&lt;br /&gt;Short example:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// Bring in some C headers for the operation bodies&lt;br /&gt;include &amp;lt;stdio.h&amp;gt;;&lt;br /&gt;include &amp;lt;stdint.h&amp;gt;;&lt;br /&gt;&lt;br /&gt;// Declare us a register&lt;br /&gt;register uint32_t $accumulator;&lt;br /&gt;&lt;br /&gt;// Bytecode 0x00 with a single 8-bit argument&lt;br /&gt;op increment(00, amount:8) {&lt;br /&gt;  $accumulator += amount;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Bytecode 0x01 with no arguments&lt;br /&gt;op print(01) {&lt;br /&gt;  printf("%lu\n", $accumulator);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Current implementations can stop execution with return&lt;br /&gt;op halt(FF) {&lt;br /&gt;  return;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The initial tools generated a dead-simple &lt;code&gt;switch&lt;/code&gt;ed VM from my bytecode descriptions, as well as some header files for manipulating the instruction set.&lt;br /&gt;&lt;br /&gt;Newer revisions generate direct-threaded code, including functions to translate the bytecode format to threaded form on load.  I'm working on very simple stream-rewrite capabilities, for use in instruction coalescing (combining several sequential ops into one) and specialization (replacing an op with a variant depending on context).&lt;br /&gt;&lt;br /&gt;A few examples of each:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Self sends:&lt;/strong&gt; by coalescing send-to-self sequences into a virtual &lt;code&gt;self-send&lt;/code&gt; instruction, we can take advantage of the lack of polymorphism.  In particular, &lt;code&gt;self-send&lt;/code&gt; has an inline parameter that points to the body of the method to call &amp;mdash; reducing the method dispatch process to a GOTO.&lt;br /&gt;&lt;strong&gt;Tail sends:&lt;/strong&gt; by coalescing a send-return sequence into a special &lt;code&gt;tail-send&lt;/code&gt; instruction &amp;mdash; unavailable in the raw bytecode &amp;mdash; we can perform tailcall elimination.&lt;br /&gt;&lt;strong&gt;Tail recursion:&lt;/strong&gt; by further specializing the instruction when (a) the receiver is &lt;code&gt;self&lt;/code&gt; and (b) the message is the same that invoked the current method, we can perform tail recursion elimination using a particularly lightweight sequence.  (M1 optimized both tail sends and tail recursion through dedicated bytecodes.)&lt;br /&gt;&lt;strong&gt;Hot sends:&lt;/strong&gt; by specializing sends into a virtual &lt;code&gt;cached-send&lt;/code&gt; instruction &amp;mdash; which has a 3-deep polymorphic inline cache &amp;mdash; we can drastically reduce method lookups for the general case.&lt;br /&gt;&lt;br /&gt;You've probably noticed that those examples all involve message sends, and there's a reason for that: Smalltalk-style languages spend most of their time sending messages around, and it tends to be a slow process.  It's low-hanging fruit for optimization.&lt;br /&gt;&lt;br /&gt;One more:&lt;br /&gt;&lt;strong&gt;Opening closures (ha ha):&lt;/strong&gt; the relatively expensive &lt;code&gt;block&lt;/code&gt; instruction, which creates a literal Block, can be specialized to a &lt;code&gt;contained-block&lt;/code&gt; instruction.  This requires that the block be entirely self-contained: no references to the enclosing context's variables, and no non-local return instructions.  In this case, the enclosing activation records need not be reified onto the heap.&lt;br /&gt;&lt;br /&gt;Some of these virtual-instruction transformations are working now; I hope to have the rest in place shortly.&lt;br /&gt;&lt;br /&gt;(Incidentally, the entire system is under 1000 lines of Ruby, plus a 134-line description of the virtual machine.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-114034893333322346?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/114034893333322346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=114034893333322346' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114034893333322346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/114034893333322346'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/virtual-machine-generators-are-fun-way.html' title='Virtual machine generators are a fun way to spend Saturday night!'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113998655207098253</id><published>2006-02-14T22:36:00.000-08:00</published><updated>2006-02-14T23:31:57.466-08:00</updated><title type='text'>Reinventing Forth</title><content type='html'>There's a saying to the effect that any sufficiently complex program or runtime will wind up reimplementing most of Common Lisp.  (I mostly hear that from Lispers, so add salt to taste.)&lt;br /&gt;&lt;br /&gt;Well, you can imagine how surprised I was to see someone &lt;a href="http://www.cs.ualberta.ca/~amaral/cascon/CDP05/slides/CDP05-berndl.pdf"&gt;reinventing Forth&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In an indirect threaded interpreter, each op &amp;mdash; let's call them &lt;em&gt;words&lt;/em&gt;, for the hell of it &amp;mdash; is represented by an index into some table holding an address to the code.  (Or, in Forth, an address of a word definition, which contains an address of the code to run.)&lt;br /&gt;&lt;br /&gt;In a direct-threaded interpreter, each words is represented by the address of the code itself, so the interpreter &amp;mdash; which we'll call &lt;em&gt;NEXT&lt;/em&gt; &amp;mdash; is basically a repeated indirect jump.&lt;br /&gt;&lt;br /&gt;At least one Forth saw the obvious next step in performance: replace each reference to a compiled word with a CALL instruction to its address, instead of the address.  (This isn't a huge leap for Forth.  Direct-threaded Forths usually have a CALL instruction in the word definition's code slot anyway.)  On the machine in question (I don't remember which), they used a within-segment jump instruction, and were able to squeeze it the same space that would have been required for the direct-threaded address.&lt;br /&gt;&lt;br /&gt;Evidently, this approach has been rediscovered, under the name "context threading."  &lt;br /&gt;&lt;br /&gt;Context threading does bring a few significant advancements to the table: it generates the calls at runtime from the original bytecode, and inlines basic flow control among all those CALL instructions.  This isn't possible in Forth without a lot of trickery, for the same reason it's difficult in Smalltalk: there are no built-in flow control mechanisms.  However, high-performance subroutine-threaded Forths will inline short, common words &amp;mdash; and you don't get much shorter or more common than IF/ELSE/THEN.&lt;br /&gt;&lt;br /&gt;Speaking of which, context threading seems to rely on the original bytecode to resolve flow control operations, where Forth would simply modify the return address.&lt;br /&gt;&lt;br /&gt;(Incidentally: yes, this is one of the two tricks I used in the Mongoose interpreter to improve indirect branch prediction.  Forth has a lot of good ideas to steal.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113998655207098253?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113998655207098253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113998655207098253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113998655207098253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113998655207098253'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/reinventing-forth.html' title='Reinventing Forth'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113997860019484836</id><published>2006-02-14T20:21:00.000-08:00</published><updated>2006-02-14T20:43:20.243-08:00</updated><title type='text'>It seems the Mongoose interpreter wasn't half bad.</title><content type='html'>I worked on the interpreter for my Smalltalk-like language, Mongoose, through 2004 and the first bit of 2005.  I eventually abandoned it, mostly because work became too stressful for me to sustain a major side project, but also because I had always looked at the interpreter as throwaway code on the way to JIT compilation.&lt;br /&gt;&lt;br /&gt;(I actually had basic JIT working on PowerPC, using a dastardly hack involving memcpy and GCC's address-of-label operator.  Never got it working on x86, where all non-academic languages must run, and I didn't know enough x86 at the time to debug it.)&lt;br /&gt;&lt;br /&gt;However, I've come 'round on since then, and have realized three things.&lt;br /&gt;1. There's a place in the world for interpreted languages.  Even the large enterprise systems, which I was explicitly targetting with Mongoose, aren't CPU-bound in most cases, and interpreters can often run in a fraction of the RAM of native code &amp;mdash; look at Forth.&lt;br /&gt;2. Even if I had a working runtime compiler, putting the JIT in "JIT compiler" &lt;em&gt;requires&lt;/em&gt; a good interpreter.  You don't want to compile &lt;em&gt;all&lt;/em&gt; your code, only the code that needs it &amp;mdash; the vast majority of the system will probably remain interpreted.  (My Mongoose "JIT" compiled at class load time, which is less than optimal.)&lt;br /&gt;3. My interpreter wasn't half bad.&lt;br /&gt;&lt;br /&gt;More on that last point, because it surprised the hell out of me.&lt;br /&gt;&lt;br /&gt;Lacking any formal CS education, I tend to come across concepts in the field in a different order than most.  For example, SSA form is intuitively obvious to me, and was how I implemented my prototype type-inference system for Mongoose &amp;mdash; so I was pretty confused when I finally bought a book on compilers a few months ago.  All the inital techniques they were describing seemed unnecessarily complex, dealing with changing values for names and the like.  (They were building up to SSA, which they covered in chapter 9.)  On the other hand, some of the really fundamental stuff &amp;mdash; like basic blocks and optimizing out common cases on the control-flow graph &amp;mdash; I had approximated, but hadn't nailed in the way they described.&lt;br /&gt;&lt;br /&gt;So, I grade my performance by tracking down interesting papers online, and figuring out how far behind them I am.  I do okay in some areas (Bracha and Unger's 2004 paper on OO metamodels pretty much describes Mongoose) and really poorly in others &amp;mdash; as is expected, for us liberal arts types.&lt;br /&gt;&lt;br /&gt;In the past week or so I've been collecting papers on interpreter design, and in some areas I seem to be close to the state-of-the-art.&lt;br /&gt;- The technique I call &lt;em&gt;instruction coalescing&lt;/em&gt; &amp;mdash; converting common sequences of VM ops into larger meta-ops that can be more easily optimized &amp;mdash; seems to be called &lt;em&gt;superinstructions&lt;/em&gt; and &lt;em&gt;specialization&lt;/em&gt; in the literature.  (Strangely, I haven't found anyone using my technique for reducing indirect branch misprediction &amp;mdash; but I'm sure &lt;em&gt;somebody&lt;/em&gt; beat me to it.)&lt;br /&gt;- There are a few interpreters floating around that use my dastardly hack for compilation; most call it &lt;em&gt;catenation&lt;/em&gt;, which makes sense: I'm using GCC's optimizer at build time, and simply stringing sections of its output together.&lt;br /&gt;- The techniques I used for stack-allocating objects when context permits will be in Java 6.  (This may have been around for years, though.)&lt;br /&gt;&lt;br /&gt;There's a great report called &lt;a href="https://www.cs.tcd.ie/publications/tech-reports/reports.05/TCD-CS-2005-61.pdf"&gt;Optimizations for a Java Interpreter Using Instruction Set Enhancement&lt;/a&gt; that covers the techniques I've been using in Mongoose, so I'm glad I'm not totally off-base.  They don't use my technique for optimizing indirect branch prediction, which may very well mean it sucks &amp;mdash; I haven't done enough profiling.&lt;br /&gt;&lt;br /&gt;I'm working on the interpreter again, having found some neat techniques I hadn't derived.  We'll see where it goes; the old Mongoose interpreter beat the pants off Ruby 1.8 in most benchmarks, but my error handling wasn't nearly as well-developed, and I didn't test any of the higher-performance Ruby VMs that are available.&lt;br /&gt;&lt;br /&gt;(...yes, this is what I do on Valentine's Day.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113997860019484836?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113997860019484836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113997860019484836' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113997860019484836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113997860019484836'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/it-seems-mongoose-interpreter-wasnt.html' title='It seems the Mongoose interpreter wasn&apos;t half bad.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113978392886640000</id><published>2006-02-12T14:00:00.000-08:00</published><updated>2006-02-14T20:45:08.673-08:00</updated><title type='text'>Variable-arity parameterized types</title><content type='html'>Language geek that I am, I've been reading up on all sorts of type systems in the past few years.&lt;br /&gt;&lt;br /&gt;Mostly, I've been interested in ways to statically typecheck dynamic OO languages, like Self &amp;mdash; but I've also been interested in how different OO languages implement parameterized types.&lt;br /&gt;&lt;br /&gt;I've noticed a common problem: most languages cannot even describe the types of their own methods.  (Strongtalk makes an exception for typing Smalltalk-style blocks, but it's not a general solution.)&lt;br /&gt;&lt;br /&gt;Before tackling methods, let's take a reasonably common case.  We want a class called Tuple, instances of which contain a fixed number of objects of different, specific, types.  So, the base Tuple class could be specialized to represent key-value pairs in a map, or (*gag*) multiple return values from a function.  (The astute reader sees another obvious use, but we'll get to that shortly.)&lt;br /&gt;&lt;br /&gt;How could we define this Tuple in a generic way?  In C++, Java, Eiffel, and most other languages (possibly including Strongtalk, though I'd love to be proven wrong), you can't.  The closest you can come is to define a different Tuple class for each length &amp;mdash; say, Tuple1&amp;lt;A&amp;gt;, Tuple2&amp;lt;A, B&amp;gt;, Tuple3&amp;lt;A, B, C&amp;gt;, etc.  I don't think I'm the only one who looks at this solution and says, "Ewww."&lt;br /&gt;&lt;br /&gt;Having learned and rejected Python shortly before I started work on Mongoose, tuples struck me as a useful abstraction, and I wanted Mongoose's type system to describe them.  Here's a pseudocode Tuple in pseudo-Mongoose.  (Brief syntax note: a generic class is applied to parameters as Class(Parameters), just as a function is applied as function(parameters).)&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Tuple(T+) {&lt;br /&gt;  method get(index : Integer) : T[index] { ... }&lt;br /&gt;  method set(index : Integer, element : T[index]) { ... }&lt;br /&gt;  method positionType(index : Integer) : Class(T[index]) { T[index] }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Tuple's formal parameter &lt;code&gt;T+&lt;/code&gt; indicates that the class can be specialized on 1..&lt;var&gt;n&lt;/var&gt; classes.  The value of &lt;code&gt;T&lt;/code&gt; is available as an ordered list, both for typechecking at development time, and for access by specialized subclasses at runtime (as shown in the body of &lt;code&gt;positionType&lt;/code&gt;).  (Implementation of a variable number of slots to store the elements is hairier, and I've omitted it.)&lt;br /&gt;&lt;br /&gt;I went to all this nasty work so that Mongoose could statically type its closures and methods.  We wind up with something like the following for the Block object (equivalent to a lambda function with environment closure):&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Block(A*, R) {&lt;br /&gt;  method argumentType(position : Integer) : Class(A[position]) { A[position] }&lt;br /&gt;  method returnType() : Class(R) { R }&lt;br /&gt;  method invoke(parameters : A) : R { ... }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The formal parameter &lt;code&gt;A*&lt;/code&gt; specifies zero or more classes.  These variable-arity parameters are bound to Tuples at runtime (and handled through trickery at compile time).  For example, for the type application &lt;code&gt;Block(Integer, Integer, String)&lt;/code&gt;, &lt;code&gt;A&lt;/code&gt; within an instance would have the type &lt;code&gt;Tuple(Integer, Integer)&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So, say you have an anonymous block like the following, which takes an Integer and tells you if it's bigger than some constant.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;{ x : Integer | x &gt; 42 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Blocks like this are frequently used in Mongoose and Smalltalk to filter collections and the like.  I've typed the block's parameter explicitly here; normally, this can be inferred from context.  Integer's published &lt;s&gt;contract&lt;/s&gt; &amp;mdash; sorry, Mr. Meyer &amp;mdash; &lt;em&gt;specification&lt;/em&gt; for &lt;code&gt;&amp;gt;&lt;/code&gt; says it returns a Boolean, so the return type of the block can be inferred.&lt;br /&gt;&lt;br /&gt;So, the type of this expression is &lt;code&gt;Block(Integer, Boolean)&lt;/code&gt;.  If anyone were to inspect its class, they'd find that the return type is &lt;code&gt;Boolean&lt;/code&gt; and the parameter list is &lt;code&gt;&amp;laquo;Integer&amp;raquo;&lt;/code&gt; (using the Tuple literal syntax that Americans can't type).&lt;br /&gt;&lt;br /&gt;The real key here is that this isn't a special feature for standard library classes like Block &amp;mdash; this is a generic mechanism (pun intended) applicable to user classes.&lt;br /&gt;&lt;br /&gt;Now, after I designed this section of Mongoose, I learned Dylan.  Dylan's ludicrously expressive type system &amp;mdash; particularly the notion of &lt;em&gt;restricted types&lt;/em&gt;, like "Integers between 2 and 12" &amp;mdash; really impressed me.  I'm looking at ways to integrate this flexibility into Mongoose's parameterized types, preferably in an elegant fashion.  (Fortunately, like C++, the parameter bindings are not necessarily restricted to classes, and are available at runtime.)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit&lt;/strong&gt; in response to comments: yes, restricted types would help me constrain the type-array references in that Mongoose code up there at compile time.  This is why I want them (among many other reasons).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113978392886640000?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113978392886640000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113978392886640000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113978392886640000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113978392886640000'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/variable-arity-parameterized-types.html' title='Variable-arity parameterized types'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113972997274771639</id><published>2006-02-11T23:27:00.000-08:00</published><updated>2006-02-11T23:39:32.756-08:00</updated><title type='text'>Commutative arguments</title><content type='html'>Had a sick thought today.&lt;br /&gt;&lt;br /&gt;In considering the binary operator problem (mentioned in &lt;a href="http://cliffhacks.blogspot.com/2006/02/multi-method-dispatch-operators-and.html"&gt;my post on multimethods a few days back&lt;/a&gt;), I thought, "What if certain functions could define themselves as order-insensitive?"&lt;br /&gt;&lt;br /&gt;The canonical example seems to be a function for testing if two objects are equal, which we'll call &lt;code&gt;equals(a, b)&lt;/code&gt;.  Equality, in my mind, is commutative, like addition: &lt;code&gt;equals(a, b)&lt;/code&gt; should always have the same result as &lt;code&gt;equals(b, a)&lt;/code&gt;.  (Thus, &lt;code&gt;equals(equals(a, b), equals(b, a))&lt;/code&gt;.)&lt;br /&gt;&lt;br /&gt;In a lot of situations, you don't want objects of two different classes to &lt;em&gt;ever&lt;/em&gt; be equal.  I would argue that numeric types are an exception: if I have the number 5 represented as a base-2 integer, and as an arbitrary-precision decimal type, they can be interconverted without a loss of data, and thus should be equal.&lt;br /&gt;&lt;br /&gt;Now, people wanting to compare Integers and Decimals might write the comparison either way &amp;mdash; or even not know which value is which type when the comparison is written.  Traditionally, if you wanted to define variants of &lt;code&gt;equals&lt;/code&gt; to cover this case, you'd have to write two functions &amp;mdash; if your language even allows it:&lt;br /&gt;&lt;code&gt;equals(Integer, Decimal)&lt;/code&gt;&lt;br /&gt;&lt;code&gt;equals(Decimal, Integer)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;What if, instead, the &lt;code&gt;equals&lt;/code&gt; function would reorder its arguments as necessary?  (Assume the runtime order of evaluation is fixed, in case you have side effects in your argument expressions.)  Only one of these two declarations would be necessary &amp;mdash; and, in fact, declaring both would be an error.&lt;br /&gt;&lt;br /&gt;Addition and any other commutative operation would also benefit.&lt;br /&gt;&lt;br /&gt;Now, of course, this doesn't solve the binary-operator problem for non-commutative operations like division, but it might be food for thought.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113972997274771639?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113972997274771639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113972997274771639' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113972997274771639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113972997274771639'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/commutative-arguments.html' title='Commutative arguments'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113972919432162240</id><published>2006-02-11T23:06:00.000-08:00</published><updated>2006-02-11T23:26:34.366-08:00</updated><title type='text'>More on multimethods</title><content type='html'>Ran across Millstein and Chamber's 2002 paper, &lt;cite&gt;Modular Statically Typed Multimethods&lt;/cite&gt;.  Based on Chambers' work on Cecil, it presents a much cleaner, logically-consistent way of doing multimethods.&lt;br /&gt;&lt;br /&gt;As a result, I am far less suspicious of them than I was a few days ago.&lt;br /&gt;&lt;br /&gt;&amp;lt;aside&amp;gt;&lt;br /&gt;Computer science papers have an amazing knack for being opaque.  Perhaps that's why good programming books are so prized.  The entire meat of this paper could have been covered in a couple pages of source examples and discussion, with an appendix for the formal definitions &amp;mdash; as is, it's 47 pages long.&lt;br /&gt;&lt;br /&gt;(Literally.  I use "forty-seven" like the Hebrew scriptures use 40, as an unspecified but ludicrous length, like "enter your forty-seven digit extension after the beep."  This paper, however, is actually 47 pages long.)&lt;br /&gt;&lt;br /&gt;But of course, a nicely tech-written summary wouldn't have made ECOOP.&lt;br /&gt;&lt;br /&gt;Anyway.&lt;br /&gt;&amp;lt;/aside&amp;gt;&lt;br /&gt;&lt;br /&gt;Their system, System E, still strikes me as iffy in the face of runtime-loaded code.  Java's ability to load and unload code on the fly is the source of a lot of its power &amp;mdash; it's the feature that allows application servers and really-well-integrated IDEs &amp;mdash; and I intend to preserve it in Mongoose.  &lt;br /&gt;&lt;br /&gt;However, I think System E can be easily adapted for runtime loading.  It does some link-time typechecking to verify consistency, and if linking happens to occur during execution, no biggie.&lt;br /&gt;&lt;br /&gt;It still bothers me that calling a function &lt;code&gt;foo&lt;/code&gt; might get me two different code paths before and after loading a module, depending on the (surprise) types of the arguments.  This is mostly a security issue for me: if a module is able to stub-out some &lt;code&gt;hasPrivilegedAccess&lt;/code&gt; function on load, all hell breaks loose.&lt;br /&gt;&lt;br /&gt;System E defines inter-module restrictions that could be used to control some of this; the rest could be left to the language security model, perhaps marking some functions as non-overrideable (Java's &lt;code&gt;final&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;Alternatively, if the language can partition loaded code off in its own little sandbox (a la Java's pending Partition feature), perhaps function overloads could be prevented at the partition level.&lt;br /&gt;&lt;br /&gt;I'm tinkering on a design for Mongoose that leverages these ideas.  More to come.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113972919432162240?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113972919432162240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113972919432162240' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113972919432162240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113972919432162240'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/more-on-multimethods.html' title='More on multimethods'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113938590663986334</id><published>2006-02-07T23:39:00.000-08:00</published><updated>2006-02-08T00:05:06.653-08:00</updated><title type='text'>Prototypes and Classes</title><content type='html'>Class- and Prototype-based OO languages are equivalent.  I don't just mean equivalent like any two Turing-complete systems &amp;mdash; they're equivalent through a simple transformation, like tail recursion and iteration.&lt;br /&gt;&lt;br /&gt;Prototype-based languages are distinguished by the fact that objects can have their own unique behavior and structure.  You can add a method or slot to an individual object instance, rather than having to modify some class that defined it.  (The benefits in UI programming are obvious &amp;mdash; hint: no more action listeners, just redefine a method on that particular button.)&lt;br /&gt;&lt;br /&gt;Under the hood, however, prototype-based &lt;em&gt;runtimes&lt;/em&gt; usually have &lt;em&gt;behavior&lt;/em&gt; objects that back the object instances.  An instance will contain some number of data slots, and a reference to its &lt;em&gt;behavior&lt;/em&gt;, where the actual methods are stored, along with references to its delegates (similar to parent-types in class-based languages).  Multiple instances can share a single behavior object, which dramatically reduces memory requirements.&lt;br /&gt;&lt;br /&gt;Now, the methods are stored on the behavior, which may be shared by many instances, but you can still add a method to a particular instance &amp;mdash; because the behavior is copy-on-write.  When you add a slot or a method to an instance with a shared behavior, it creates a new behavior containing your modification, which delegates back to (read: inherits from) the original.  The modified instance is switched to use the new behavior, and voila.&lt;br /&gt;&lt;br /&gt;This preserves the prototype semantics of the language, while reducing memory footprint and improving cache performance.&lt;br /&gt;&lt;br /&gt;It also looks a lot like a class-based object system &amp;mdash; and, in fact, a sufficiently flexible class-based object system can achieve exactly the same behavior.&lt;br /&gt;&lt;br /&gt;Translating from the prototype world to the class world, adding a method or slot to an instance creates a new class (behavior) containing the new method/slot, inheriting from (delegating to) the original class, and changes the instance's class to the new subtype.&lt;br /&gt;&lt;br /&gt;Very few class-based object systems are this flexible &amp;mdash; Java, for example, cannot change the class of an object on the fly.  (In fact, only Smalltalk and Ruby spring to mind, though I'm sure someone will pipe up and insist it can be done in CLOS.)  I'd like to see this sort of thing become widely available; I'm not a fan of prototype-based languages in general, but this would be a very powerful feature in a class-based language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113938590663986334?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113938590663986334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113938590663986334' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113938590663986334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113938590663986334'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/prototypes-and-classes.html' title='Prototypes and Classes'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113938439336338670</id><published>2006-02-07T23:14:00.000-08:00</published><updated>2006-02-07T23:39:53.406-08:00</updated><title type='text'>Multi-method dispatch, operators, and typecasting</title><content type='html'>I am suspicious of multi-method dispatch.&lt;br /&gt;&lt;br /&gt;In a language like Smalltalk, when you send a message like&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;foo process: bar with: baz&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;...you know that &lt;code&gt;foo&lt;/code&gt; will respond to the message, generally executing some method identified with &lt;code&gt;process:with:&lt;/code&gt;.  &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; have no direct say.&lt;br /&gt;&lt;br /&gt;In a language with multi-method dispatch, &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; &amp;mdash; the arguments to the message &amp;mdash; can also provide methods for handling the message.  Generally, the most specific one is chosen &lt;em&gt;at runtime&lt;/em&gt;: if &lt;code&gt;foo&lt;/code&gt; has a method for dealing with arguments of any two types, but &lt;code&gt;baz&lt;/code&gt; offers one that accepts the precise runtime types of all three objects, it is not &lt;code&gt;foo&lt;/code&gt;'s code which will execute, but &lt;code&gt;baz&lt;/code&gt;'s.&lt;br /&gt;&lt;br /&gt;As I said, I'm suspicious of this.&lt;br /&gt;&lt;br /&gt;I &lt;em&gt;like&lt;/em&gt; the ease of reasoning that single-dispatch gives me, knowing that a given object's code will execute when I call a method.  Particularly if the code for &lt;code&gt;baz&lt;/code&gt; was loaded at runtime, the method may be effectively hijacked with a result I didn't intend.&lt;br /&gt;&lt;br /&gt;However, I can think of two cases that are &lt;em&gt;dramatically&lt;/em&gt; more elegant with MMD: operators, and casting (which is effectively an operator).&lt;br /&gt;&lt;br /&gt;Smalltalk lets you name a method '+', to be called in the normal infix fashion, &lt;code&gt;a + b&lt;/code&gt;.  In that fragment, it is of course &lt;code&gt;a&lt;/code&gt;'s + method that will execute.&lt;br /&gt;&lt;br /&gt;But let's say you define a new type to represent, say, money &amp;mdash; we'll name it &lt;code&gt;Money&lt;/code&gt;.  You teach it to add integers, floats, or other numbers using a + method.  This is all well and good, so long as you write it like this:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;myMoneyAmount + someInteger&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Great.  The + method you defined for all objects of type &lt;code&gt;Money&lt;/code&gt; runs, adds the integer, returns a &lt;code&gt;Money&lt;/code&gt;.  All is well.&lt;br /&gt;&lt;br /&gt;However, if you write it&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;someInteger + myMoneyAmount&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;(which is, thanks to the commutative property, mathematically equivalent), what happens?  The + method on the built-in class &lt;code&gt;Integer&lt;/code&gt; fires up, and it may not know how to act on your &lt;code&gt;Money&lt;/code&gt; object &amp;mdash; and almost certainly will not return a new &lt;code&gt;Money&lt;/code&gt; in response!&lt;br /&gt;&lt;br /&gt;The traditional Smalltalk solution to this is, in my opinion, a hack.  It's called double-dispatch.  The code in &lt;code&gt;Integer&lt;/code&gt; would notice that the other addend isn't a known type, so it passes control into the addend using &lt;em&gt;some other method&lt;/em&gt;.  Effectively, it converts that fragment into something like&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;myMoneyAmount addedWithInteger: someInteger&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;(Why doesn't it flip it around and call the + method on the argument?  Because that could quickly become an infinite loop of back-and-forth message sends.  &lt;code&gt;addedWithInteger:&lt;/code&gt;, or whatever it's called, is defined as not performing double-dispatch.)&lt;br /&gt;&lt;br /&gt;That's a simple solution for the built-in types, but if you've got two third-party types you want to add, each must sport an &lt;code&gt;addedWithWhatever:&lt;/code&gt; method for the other &amp;mdash; when the third-party types are probably not aware of one anothers' existence.  The situation can spiral out of control.&lt;br /&gt;&lt;br /&gt;In Smalltalk, specifically, this problem is mitigated by the fact that you can add methods to other peoples' classes once they're loaded into the system.  You can construct this web of adding methods to ensure your types play nice.&lt;br /&gt;&lt;br /&gt;This is not, to me, a solution, but a workaround.&lt;br /&gt;&lt;br /&gt;You'll run into similar problems if you try to implement a generic cast method.  Smalltalks frequently have &lt;code&gt;asString&lt;/code&gt; or &lt;code&gt;asArray&lt;/code&gt; methods to convert objects to some other type.  If you wanted a generic method, like&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;foo as: Bar&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;you'd wind up having to resort to double-dispatch again.  Your &lt;code&gt;Money&lt;/code&gt; class can easily handle "as: Integer", but having &lt;code&gt;Integer&lt;/code&gt; handle "as: Money" is more difficult.&lt;br /&gt;&lt;br /&gt;Multi-method dispatch eliminates this problem entirely, by allowing your Money class to introduce an &lt;code&gt;as:&lt;/code&gt; method that is used &lt;em&gt;when a Money object is the argument, not just the receiver&lt;/em&gt;.  (Yes, pedants, in MMD there is no receiver per se.)&lt;br /&gt;&lt;br /&gt;This is one situation where I would &lt;em&gt;like&lt;/em&gt; the dispatch of the method to be determined at runtime.&lt;br /&gt;&lt;br /&gt;C++ solves it a little differently, by having both member functions for operators, and free-floating functions that overload &lt;code&gt;operator+&lt;/code&gt; depending on the argument types, but the result is the same as MMD.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So, for this sort of problem, MMD is appealing.  I've been thinking about this for a while, and there's an obvious place in the Mongoose language to hook MMD if necessary (namely, by providing implementations directly for the Class-independent Method Contract Identifier &amp;mdash; effectively, C++'s approach).&lt;br /&gt;&lt;br /&gt;I suspect there's a compromise, or perhaps an alternative technique.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113938439336338670?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113938439336338670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113938439336338670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113938439336338670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113938439336338670'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/multi-method-dispatch-operators-and.html' title='Multi-method dispatch, operators, and typecasting'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113920050695854432</id><published>2006-02-05T20:33:00.000-08:00</published><updated>2006-02-05T20:35:06.970-08:00</updated><title type='text'>Update: no updates.</title><content type='html'>In case anyone's actually reading this, yes, I will post stuff soon.&lt;br /&gt;&lt;br /&gt;Since I created this blog, I haven't been able to discuss most of what I'm doing.  I'm starting to get settled, so I'll be doing more personal hacking soon.&lt;br /&gt;&lt;br /&gt;Currently, I'm playing with Facelets, and I'm awfully tempted to write up a JSF tutorial that eschews JSP.  So much easier!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113920050695854432?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113920050695854432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113920050695854432' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113920050695854432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113920050695854432'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/02/update-no-updates.html' title='Update: no updates.'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21310324.post-113787271633871971</id><published>2006-01-21T11:17:00.000-08:00</published><updated>2006-01-21T11:54:30.156-08:00</updated><title type='text'>Making those 'Universal Binaries' a bit more universal</title><content type='html'>Some of you may be familiar with Cesta, my network analyzer.  I'm starting to get settled in California, so I'm beginning to hack on it again.&lt;br /&gt;&lt;br /&gt;Like any Mac developer in January of 2006, I'm interested in having my app be a Universal Binary, so it will run on both PowerPC and x86.  Apple provides pretty good support for this.  However, there's one minor gap:&lt;br /&gt;&lt;br /&gt;Tiger (10.4) uses GCC 4.0.  Panther (10.3.x)  uses GCC 3.3.  There are minor incompatibilities and feature gaps between these &amp;mdash; for example, on Tiger, I can use an accelerated dispatch routine for Objective-C message sends.  The C++ ABI is also subtly different, and tends to break some routine language features.&lt;br /&gt;&lt;br /&gt;Building a Universal Binary for 10.3 PPC and 10.4 x86 is straightforward, but there's no Apple-supported way to build a three-way binary: 10.3 PPC, 10.4 PPC, 10.4 x86.  Sure, I could use weak linking to use the 10.4 API from a 10.3 binary &amp;mdash; but that doesn't get me the compiler and ABI changes I want from GCC 4.0, which will &lt;em&gt;only&lt;/em&gt; run on 10.4.  (With some of the C++ changes, the binary won't even get past dyld.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, I've been developing for Unix a lot longer than Mac OS X has been around, and Unix has this marvelous family of system calls, &lt;code&gt;exec(3)&lt;/code&gt;.  They allow you to replace your current process image with another &amp;mdash; you keep the same process, with the same PID and RUID, but the running program changes.  This is used all over Unix, particularly in the time-honored &lt;code&gt;fork&lt;/code&gt;/&lt;code&gt;exec&lt;/code&gt; sequence.  Of course, these are available in OS X.&lt;br /&gt;&lt;br /&gt;"So I realize," I realized, "that I could use this to effectively change ABIs on the fly."&lt;br /&gt;&lt;br /&gt;Here's how it works.&lt;br /&gt;The official binary (Contents/MacOS/$APPNAME) is a Mach-O fat^H^H^HUniversal binary, containing code for ppc (compiled against 10.3.9 using gcc 3.3) and x86 (compiled against 10.4 using gcc 4.0.1).&lt;br /&gt;&lt;br /&gt;However, using an auxiliary target, I also include a non-fat copy, containing only ppc code, compiled using gcc 4.0.1 against the 10.4 SDK.&lt;br /&gt;&lt;br /&gt;Normal developers would, at this point, have their users download one version or the other &amp;mdash; and if I &lt;em&gt;wanted&lt;/em&gt; my app to feel like a crappy Windows package, I would do just that.&lt;br /&gt;&lt;br /&gt;Instead, I've dropped the following code fragment into the &lt;code&gt;main&lt;/code&gt; function.  It ain't pretty, because it's a first crack that I wrote some fifteen minutes ago, but it &lt;em&gt;works&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;It&lt;br /&gt;1. Checks for GCC 3.3.  This means it's the PowerPC 3.3 binary.&lt;br /&gt;2. Checks for Tiger.&lt;br /&gt;3. Tries to construct a path to the Tiger-optimized PPC binary.&lt;br /&gt;4. execs it, thereby replacing the current process.&lt;br /&gt;5. If anything goes wrong, the PPC 3.3 binary is used.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;#if __GNUC__ == 3&lt;br /&gt;  // We're the gcc3.3 PPC binary.  Check for Tiger.&lt;br /&gt;  // If any error occurs, simply fall back to running this version.&lt;br /&gt;  SInt32 MacVersion;&lt;br /&gt;  if(Gestalt(gestaltSystemVersion, &amp;MacVersion) == noErr) {&lt;br /&gt;    if(MacVersion &gt;= 0x1040) {&lt;br /&gt;      &lt;br /&gt;      // On 10.4 or above.  Let's do nasty things to the runtime.&lt;br /&gt;      char *lastSlash = strrchr(argv[0], '/');&lt;br /&gt;      if(lastSlash != NULL) {&lt;br /&gt;        // Build a path to the Tiger binary.&lt;br /&gt;        char binaryPath[lastSlash - argv[0] + 1 + 13 + 1];&lt;br /&gt;        strncpy(binaryPath, argv[0], lastSlash - argv[0] + 1);&lt;br /&gt;        strncpy(binaryPath + (lastSlash - argv[0]) + 1, "TigerExecTest", 14);&lt;br /&gt;        fprintf(stderr, "%s\n", binaryPath);&lt;br /&gt;        char *execArgs[argc + 1];&lt;br /&gt;        memcpy(execArgs, argv, argc * sizeof(char *)); &lt;br /&gt;        execArgs[argc] = 0;&lt;br /&gt;        execv(binaryPath, execArgs);&lt;br /&gt;&lt;br /&gt;        // Oh crap.  I guess we'll stick with the 3.3 version.&lt;br /&gt;        perror("Exec failed");  &lt;br /&gt;      }                 &lt;br /&gt;&lt;br /&gt;    }           &lt;br /&gt;  }     &lt;br /&gt;#endif&lt;br /&gt;  return NSApplicationMain(argc,  (const char **) argv);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Error handling could be better, but there you have it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21310324-113787271633871971?l=cliffhacks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cliffhacks.blogspot.com/feeds/113787271633871971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21310324&amp;postID=113787271633871971' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113787271633871971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21310324/posts/default/113787271633871971'/><link rel='alternate' type='text/html' href='http://cliffhacks.blogspot.com/2006/01/making-those-universal-binaries-bit.html' title='Making those &apos;Universal Binaries&apos; a bit more universal'/><author><name>Cliff L. Biffle</name><uri>http://www.blogger.com/profile/16279048507944234081</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
