| Forth is bliss |
[Mar. 22nd, 2008|10:03 am] |
I'm programming in Forth on an exotic island and life is just fine.
I've done two weeks of serious hacking now: the first to bring up
Forth on the Keil MCB2100 board and the second to write drivers
and make some extensions to Forth. Serious fun!
Forth is amazing. There's hardly any compiler or runtime system and
yet it has all the sophistication of Lisp. This feels like discovering
Gödel, Escher, Bach faithfully expressed in a few dozen cave
paintings.
The best part about embedded programming is starting from scratch
without using a single line of code that we didn't write outselves.
Right now we don't have memory protection, dynamic memory allocation,
concurrency, garbage collection, etc. So we're going to rediscover
first-hand at what point it's worth developing these fancy features.
Truly we're retreading some giant steps :-)
Here's some Forth I wrote that may be clever or stupid, I'm not sure
which yet:
\ Running time profiling: t( ... )t
: t(
r> tick ( r t1 )
>r >r ( r: t1 r )
;
: )t
tick r> r> ( t2 r t1 )
swap >r ( t2 t1 )
- ( tdelta )
. ." ms" cr
;
Ah the rapture of learning a new programming language :-) |
|
|
| Comments: |
From: (Anonymous) 2008-03-22 05:42 am (UTC)
Factor | (Link)
|
I'm sure you've heard of it, but just in case you haven't you should look at Factor. It's a forth like language, with all of those things you are rediscovering. http://factorcode.org/
From: rfc1149.net 2008-03-22 08:40 am (UTC)
Messing with the return stack | (Link)
|
Nice to see a Forth post.
You could also do: (totally untested)
: t( postpone tick postpone >r ; immediate
: (t)) tick swap - . ." ms" cr ;
: t) postpone r> postpone (t)) ; immediate
which doesn't make any assumption about the return stack being anything other than a secondary stack ("retain stack" as Factor calls it). And it adds less runtime overhead.
This also allows you to let profiling information in place for your critical routines without any penalty if you don't want to use it:
0 value profiling? (change 0 to 1 to activate profiling)
: t( profiling? if postpone tick postpone >r then ; immediate
: (t)) tick swap - . ." ms" cr ;
: t) profiling? if postpone r> postpone (t)) then ; immediate
![[User Picture]](http://p-userpic.livejournal.com/56458137/11934870) | From: lukego 2008-03-22 12:26 pm (UTC)
Re: Messing with the return stack | (Link)
|
Nice!
Is there a simple backquote trick to avoid typing "postpone" so much?
I'm imagining something like:
: t( ` tick >r ` ; immediate
Edited at 2008-03-22 12:29 pm (UTC)
From: rfc1149.net 2008-03-22 03:44 pm (UTC)
Re: Messing with the return stack | (Link)
|
Not easily as you describe (you would have to handle numerical literals separately anyway, as they are put in by using 3 postpone literal rather than postpone 3 are they are not words by themselves). However, you can define ` as being a synonym for postpone:
: ` postpone postpone ; immediate
This is Forth after all :)
It has a wonderful charm for expressing yourself, and a wonderful economy of primitives; I wish it translated better to the ability to read the code of others.
I think some languages are, in a sense, too good at factoring and minimalism for their own good: by the time you're done factoring things down, only you can tell what the code means anymore. The Forth and APL families are the clear winners. The Prolog and Snobol families are perhaps runners-up, with the Lisp and Smalltalk families taking the bronze (and inching into territory where team programming seems possible).
Lots of people do regard Forth as write-only but I'll have to discover this first hand. I'm working on a codebase written by a friend who had a head-start and so far I find the code pleasantly easy to understand (and fun -- learning tricks). Hardware is pretty friendly too - I wonder if Unix's serial port interface is any easier than poking the UART registers directly?
But I do always love the shiny new language I'm learning so this is all subject to post-novelty revision later :-)
For concreteness here's the actual UART driver:
\ UART Driver:
: uart-tx? ( uart -- flag )
ULSR + ( register )
@ $20 and \ TEMT flag
;
: uart-tx ( char uart -- )
BEGIN dup uart-tx? UNTIL ( char uart )
UTHR + !
;
: uart-rx? ( uart -- flag )
ULSR + ( register )
@ $01 and \ RDR flag
;
: uart-rx ( uart -- char )
BEGIN dup uart-rx? UNTIL ( uart )
URBR + @
;
And here's the higher-level string-based parts:
\ Convert from file descriptor number to UART base address.
: FD->UART ( fd -- uart )
CASE
0 OF $E000C000 ENDOF
1 OF $E0010000 ENDOF
ENDCASE
;
: sys-write ( c-addr len fd -- ior )
dup fd-ok? IF
fd->uart ( c-addr len uart )
swap rot ( uart len c-addr )
bounds DO ( uart )
i c@ over ( uart char uart )
uart-tx ( uart )
LOOP
drop 0 ( ior )
ELSE
drop drop drop
9
THEN
;
\ FIXME: Not tested.
: sys-read ( c-addr len fd -- sz ior )
dup fd-ok? IF
over >r \ r: len
fd->uart ( c-addr len uart )
swap rot ( uart len c-addr )
bounds DO ( uart )
dup uart-rx ( uart char )
i c! ( uart )
LOOP
r> 0 ( sz ior )
ELSE
drop drop drop
0 9
THEN
;
ok and in honesty there's a little more code for setting up the baud rate:
\ Initialize pins for UART functions.
: init-tty-PINSEL ( fd -- )
0 = IF
1 0 io-0-function \ P0.0 Function TxD UART0
1 1 io-0-function \ P0.1 Function RxD UART0
ELSE
1 8 io-0-function \ P0.8 Function RxD UART1
1 9 io-0-function \ P0.8 Function RxD UART1
THEN
;
\ Convert from file descriptor number to UART base address.
: FD->UART ( fd -- uart )
CASE
0 OF $E000C000 ENDOF
1 OF $E0010000 ENDOF
ENDCASE
;
: uart-baud-divisor ( baud -- )
16 * \ baud*16
dup PCLK + 1 - \ baud*16 baud*16+PCLK-1
swap / \ (pclk+baud*16-1)/baud*16 ( rounded divisor )
;
: set-tty-baud ( baud fd -- )
FD->UART >r ( baud r: uart )
$80 r@ ULCR + !
uart-baud-divisor
dup $FF and r@ UDLL + !
8 rshift r@ UDLM + !
$4F r@ UFCR + !
$33 r@ ULCR + !
r> drop
;
: init-tty ( baud fd -- )
dup init-tty-PINSEL ( baud fd )
set-tty-baud
;
so it does add up a bit but it's pretty straightforward. :-)
From: grettke 2008-03-22 11:35 pm (UTC)
What do you do for living? | (Link)
|
In Tibet working on the OLPC XO, now Thailand coding Forth... are you guys hiring? :)
I'd reckon that most programming jobs could be done from here. Work on your boss :-)
Where is here? Looks nice :)
This is Koh Phi Phi in Thailand. Beautiful beaches, great food, and wireless internet :-) but the perfect weather will turn stormy hereabouts in the coming weeks so I don't recommend coming this way now.
From: (Anonymous) 2008-04-08 04:21 am (UTC)
Sooo jealous | (Link)
|
Maybe I need to reconsider my big company ways and try another startup... someplace with coconuts!
-Tim
| |