FlashForth: for PIC and Atmega Wiki
Brought to you by:
oh2aun
\ ************************************************ \ Utility words for FlashForth 4.8 \ MJM 9/17/12, 7/14/13 \ MJM 11/1/13 \ Some by Mike Miller \ Some by Mikael Nordman, mod by MJM \ www.moonvalleycircuits.com \ ************************************************ fl+ \ allow flash writes decimal utilwords marker utilwords hex : 4+ ( n --- n+4 ) 4 + ; : fcon \ make constant in flash that can be written flash create , does> @ ; \ to write: <value> ' <name> 4+ ! : f2con \ make 2constant in flash that can be written flash create swap , , does> 2@ ; \ to write: <dvalue> ' <name> 4+ 2! : fcon! ( n, cfa --- ) \ write flash constant fl+ 4+ ! iflush fl- ; : f2con! ( d, cfa --- ) \ write flash 2constant fl+ 4+ 2! iflush fl- ; : fcmove ( addr1 faddr2 u -- ) \ cmove into flash fl+ cmove iflush fl- ; : ? ( addr -- ) @ . ; : u? ( addr -- ) @ u. ; : c? ( addr -- ) c@ . ; : 0! ( addr -- ) 0 swap ! ; : off ( addr -- ) \ set addr false 0 swap ! ; : on ( addr -- ) \ set addr true true swap ! ; : pick ( xu ... x0 u -- xu ... x0 xu) 2* 2+ sp@ swap - @ ; : ?dup ( n -- n, n; or-- 0 ) \ dup if not zero dup if dup then ; : boolean ( n --- f ) \ convert number to boolean flag 0= 0= ; : nop ; : 4* ( n --- 4n ) 2* 2* ; : 4/ ( n --- n\4 ) 2/ 2/ ; : 2swap ( d1, d2 -- d2, d1 ) rot >r rot r> ; : scale ( b, n --- b \ scale b by 2^n) dup 0< if abs for 2/ next else for 2* next then ; : depth ( --- n ) \ depth of stack sp@ s0 @ - 2/ ; : needed ( .., n --- ) depth 1- 1+ < 0= if ." not enough stack items" abort then ; hex : combine ( l, h --- n |combine two bytes into words) 100 * + ; : split ( n --- l, h |split word int high & low bytes) 100 /mod ; : >< ( n --- n | byte-swap 16 bitt number) split swap combine ; : >w@< ( addr -- n | sign-extended fetch) w@ dup 7fff > if ffff0000 + then ; : wconvert ( addr --- | flips word at addr) dup w@ >< swap w! ; decimal : u- ( u1, u2 --- u | u1-u2 ) dup 0< 2 pick 0< not and if swap then - ; swap if u2 is negative but u1 is not : u- - ; : -dump ( addr -- ) \ dump before, after addr $10 - $40 dump ; : hdump ( addr -- ) \ hex dump before, after addr base @ swap hex -dump base ! ; : count ( addr -- addr+1, count ) \ Get count & address of counted string c@+ ; \ dup 1+ swap c@ ; : -count ( addr+1, count, --- addr ) \ Get staddr from count & address in RAM over 1- c! 1- ; : #>str ( d -- addr, cnt ) \ simple number to string & sign tuck dabs <# #s rot sign #> ; : #st1 ( d -- addr, cnt ) \ number to string w/ one dp & sign tuck dabs <# # [char] . hold #s rot sign #> ; : #st2 ( d -- addr, cnt ) \ number to string w/ two dp & sign tuck dabs <# # # [char] . hold #s rot sign #> ; : #st3 ( d -- addr, cnt ) \ number to string w/ three dp & sign tuck dabs <# # # # [char] . hold #s rot sign #> ; : $>$ ( saddr, daddr --- ) \ move counted string over c@ 1+ cmove ; : $comp ( saddr1, saddr2, -- f ) \ compare counted strings, ft if equal !p>r true swap dup c@ 1+ \ saddr2>p, --- ft, saddr1+1, count for c@+ pc@ = \ compare chr p+ rot and swap \ AND flag next drop r>p ; : strcat ( straddr1, count1, straddr2, count2 --- straddr1, count ) \ concatenate strings \ straddr1 must be in RAM >r >r \ -- straddr1, count1 R-- count2, straddr2 2dup + r> swap r@ cmove \ -- straddr1, count1 R-- count2 r> + over 1- over swap c! ; \ store new count in case we concatenate again variable dpl \ decimal point location for (number), number : (number) ( d1 addr1 --- d2 addr2 ) \ similar to FIG \ Run-time routine of number conversion. Convert an ASCII text beginning at \ addr1+ according to BASE. The result is accumulated with d1 to become d2. \ addr2 is the address of the first unconvertable digit. begin 1+ dup >r \ save addr1+1, address of the first digit, on return stack. c@ \ get a digit digit? \ A primitive. ( c n1 -- n2 tf or nx ff ) \ Convert the character c according to base to a binary \ number n2 with a true flag on top of stack. while \ successful conversion, accumulate into d1. swap \ get the high order part of d1 to the top. base @ um* \ multiply by base value drop \ drop the high order part of the product rot \ move the low order part of d1 to top of stack base @ um* \ multiply by base value d+ \ accumulate result into d1 p+ \ inc conversion flag dpl @ 1+ \ see if dpl is other than -1 if \ DPL is not -1, a decimal point was encountered 1 dpl +! \ Increment DPL, one more digit to right of decimal point then r> \ Pop addr1+1 back to convert the next digit. repeat \ If an invalid digit was found, exit the loop here. Otherwise \ repeat the conversion until the string is exhausted. drop r> ; \ Pop return stack which contains the address of the first \ non-convertable digit, addr2. : number ( addr -- d, n or ff ) \ Fig style number, with thanks to C. H. Ting \ Convert counted character string at addr to signed double integer number, \ using the current base. If a decimal point is encountered \ in the text, its position will be given in DPL, number of digits is in \ the conversion flag. \ String must have a trailing (unconvertible) chr 0 !p>r \ conversion flag 0 0 rot \ push two zero's on stack as the initial value of d . dup 1+ c@ \ get the first digit $2d = \ is it a - sign? dup >r \ Save the sign flag on return stack. negate + \ If the first digit is -, the flag is 1, and addr+1 points to \ the second digit. If the first digit is not -, the flag is 0. \ addr+0 remains the same, pointing to the first digit. -1 \ The initial value of DPL begin \ Start the conversion process dpl ! \ Store the decimal point counter (number) \ Convert one digit after another until an invalid char occurs. \ Result is accumulated into d . dup c@ \ fetch the invalid digit $2e = \ is it "." while \ it is a decimal point 0 \ A decimal point was found. Set DPL to 0 repeat \ exit here if non-convertible chr found, otherwise repeat the \ conversion process. drop \ discard addr on stack r> \ pop the flag of - sign back if dnegate \ negate d if the first digit is a - sign. then \ All done. A double integer is on stack. @p r>p \ conversion count on stack dup 0= if nip nip then ; \ drop double in no digits create stringbuff ( -- addr ) #40 allot \ a convenient string buffer : get stringbuff 1+ #40 accept stringbuff c! ; \ accept following text to buffer \ ******************************************************************* \ Copied from jt.txt by Mikael Nordman \ \ create an execution table with n entries \ each entry consists of 'nn' cell sized comparison value \ and 'an' the address of the corresponding word to be executed. \ At least two entries must be provided, the last one beeing the \ default action. \ mod 5/12/13 MJM : jte nip cell+ @ex ; : jt ( an nn n -- ) \ compile an execution table ( m -- ) \ execute aword corresponding to m flash \ MJM create dup 1- , \ store the table size for , , \ store an entry next ram \ MJM does> \ m addr dup @ \ m a n for cell+ 2dup @ = \ m a flag if \ a match was found jte rdrop exit then cell+ \ m a next \ Execute the default action. cell+ jte ; ram : tx2out ['] tx2 r0 2+ ! ; \ Set task EMIT vector to TX2 for debug \ LMI WinForth structure words by MJM 12/14/94 \ emulate CSI Mac Forth \ adapted to Flash Forth 5/10/13 MJM \ Last Revision: 5/28/13 01:06:59 PM MJM \ macforth structures variable evenstructures evenstructures on : =cells evenstructures @ if 1+ -2 and then ; : field ( n1 -- ) create , \ w, w@ if 32 bit does> @ + ; ( n2 -- n1+n2) : :aligned 2 needed swap =cells swap over field + ; : struct: :aligned ; : :member 2 needed over field + ; : byte: 1 :member ; : bytes: :member ; : string: bytes: ; : short: 2 :aligned ; : shorts: 2 * :aligned ; : long: 4 :aligned ; : longs: 4 * :aligned ; : structure flash create here 0 , 0 ( --- here, 0 ) does> @ ; ( --- n ) : structure.end 2 needed =cells swap ! ram ; \ Structure example: structure t&drecord \ time & date byte: +year byte: +month byte: +day byte: +hours byte: +minutes byte: +seconds structure.end create t&d t&drecord 4 * allot \ create a structure with 4 time & date records : @minute ( record --- minutes) \ fetch minutes from record 0 - 3 t&drecord * t&d + \ beginning of desired t&d record +minutes c@ ;
Mike Miller