<MrMobius>
is there a way to write something like [ value 1 + ] literal so that it still does what it does in compile more but can also be used in immediate mode?
<MrMobius>
as if the [ ] and literal werent there
tabemann has quit [Ping timeout: 265 seconds]
pierpal has joined #forth
boru` has joined #forth
boru has quit [Disconnected by services]
boru` is now known as boru
proteus-guy has quit [Ping timeout: 260 seconds]
proteus-dude has quit [Ping timeout: 272 seconds]
pierpal has quit [Read error: Connection reset by peer]
iyzsong-x has joined #forth
iyzsong has quit [Ping timeout: 268 seconds]
tabemann has joined #forth
iyzsong has joined #forth
iyzsong-x has quit [Read error: Connection reset by peer]
rdrop-exit has joined #forth
<rdrop-exit>
MrMobius, if you're Forth has a peephole optimizer then 5 1+ should end up compiled as 6
<rdrop-exit>
if not you could make a word to reduce the clutter
<rdrop-exit>
e.g. instead of [ foo 2 + ] literal
<rdrop-exit>
you could have something like [ foo 2 + ]#
<rdrop-exit>
If your Forth has a peephole optimizer then no need, just use: foo 2 +
<rdrop-exit>
The above assumes foo is a constant
<tabemann>
hey
<rdrop-exit>
hi tabemann!
<tp>
rdrop-exit, Zen Forth Guru!
<tp>
hey tabemann
<tabemann>
hey tp
<rdrop-exit>
hello Master Forth Technician from Down-Under (tm)
<tabemann>
zeptoforth seems almost complete, at least for the DISCOVERY board, but I don't really know how to debug it
<tp>
rdrop-exit, I have no clue about the use of " [ foo 2 + ] literal" would you mind giving a example of it's use ?
<tabemann>
[ foo 2 + ] puts the system in interpretation mode, evaluates foo, and adds 2 to it
<tp>
rdrop-exit, recently on fire Australia, then wet Australia, now sunny and humid Australia
<tabemann>
literal takes a value off the top of the stack and compiles it as literal
<rdrop-exit>
I don't think it would apply to you tp, since you're Forth has peephole optimization
<tp>
rdrop-exit, ahh
<rdrop-exit>
In a forth without peephole optimization something like:
<rdrop-exit>
10 constant foo
<tp>
tabemann, yeah, I have a comprehensive dictionary explaining individual commands but whee I have trouble is in imagining the application
<rdrop-exit>
: example ... foo 2 + ... ;
<tabemann>
basically you put everything you want evaluated immediately between brackets
<tabemann>
then, after it's been evaluated immediately, the close bracket sends you back to compilation
<tabemann>
so if you've put a value on top of the stack while executing immediately
<rdrop-exit>
would probably compile (depending on the Forth and its idiosynchracies)...
<tabemann>
you can then use LITERAL to compile that value
<rdrop-exit>
|lit|10|lit|2|+|
<tabemann>
it's very useful if one has expensive operations that you only need to evaluate once, at compile-time
<rdrop-exit>
while : example ... [ foo 2 + ] literal ... ;
<rdrop-exit>
might compile...
<rdrop-exit>
|...|lit|12|...|
<rdrop-exit>
A peephole optimizer would take care of it for you, if you're Forth doesn't have one, you have to explicitly do it yourself
<rdrop-exit>
[ puts you into interpretation state
<tp>
yes
<rdrop-exit>
you then add 2 to 10 while in interpretation state
<tp>
<tabemann> it's very useful if one has expensive operations that you only need to evaluate once, at compile-time <-- aha
<rdrop-exit>
then you get out of interpreation state with ]
<tp>
yes
<rdrop-exit>
and use LITERAL to compile the calculated literal
<tp>
yes, I can follow the syntax and what they do, I couldnt see the application
<rdrop-exit>
You could do a shorthand to make it less wordy, e.g.
<tp>
seeing the application in these cases is my difficulty
<rdrop-exit>
: ]# { x -- }( -- x ) postpone literal ] ; immediate
<tabemann>
you mean
<rdrop-exit>
a little shorter, allows you to do [ foo 2 + ]#
<rdrop-exit>
instead of [ foo 2 + ] literal
<tabemann>
: ]# { x -- }( -- x ) postpone ] postpone literal ; immediate
<rdrop-exit>
why are you postponing ] ?
<tabemann>
okay, forget about it
* tabemann
for a sec thought ] was immediate
<rdrop-exit>
In my Forth the actual syntax would be:
<rdrop-exit>
: ]# { x -- }{ -- x } lit, ] ; directive
<rdrop-exit>
but that's non-standard ;)
<rdrop-exit>
I don't have LITERAL anymore
<rdrop-exit>
just lit, which isn't immediate
<rdrop-exit>
oops wrong stack comment, try again
<rdrop-exit>
: ]# { x -- }( -- x ) lit, ] ; directive
<rdrop-exit>
It's still something to keep in mind when you're dealing with a small resident Forth that has no optimization
<tp>
thanks guys
<tabemann>
I've heavily used [ ] literal when working on math routines in the past
<tp>
I understand the application and mechanism now :)
<rdrop-exit>
cool :)
<tabemann>
where often things can be very expensive, but only needing execution once
<rdrop-exit>
Another option is to just do <calculattions> constant foo
<rdrop-exit>
*calculations
<tp>
I always have tons of time to get stuff done, so expensive operations are rarely a issue for me
<rdrop-exit>
the technique also saves dictionary space as well reducing runtime overhead
<tabemann>
I still wonder how those 64-bit fixed point values mecrisp-stellaris uses work on a platform lacking 64-bit division altogether
<rdrop-exit>
But in your case your Mecrisp Forth takes care of it for you
<rdrop-exit>
Division is best avoided altogether when possible
<tp>
tabemann, Mecrisp-Stellaris only has 32 bit division with a 64 bit result I think
<tabemann>
you mean multiplication
<rdrop-exit>
there are all sorts of tricks to avoid division by small constants
<rdrop-exit>
even C lacks double-word by single-word division
<rdrop-exit>
except perhaps as a non-standard compiler intrinsic
<rdrop-exit>
in fact C even lacks a double-word product
<tabemann>
no, you cast to __int128 and then do your product there :D
<tabemann>
yes, that's not standard
<rdrop-exit>
non-standard
<tabemann>
but both gcc and clang support it
* tabemann
is willing to use a feature if both gcc and clang have it
<rdrop-exit>
actually IIRC anything to do with 128 bits is non-standard
<tabemann>
yes
<tabemann>
even though I've run into compilers that are sufficiently standard that hey don't even support declaring variables anywhere but at the top of a block
<rdrop-exit>
never heard of that
<tabemann>
I mean local variables
<tp>
rdrop-exit, yes, in a way Mecrisp-Stellaris has made my Forth life a lot easier by taking care of so many issues
<tp>
rdrop-exit, which is ok for a tech, but would annoy a programmer I guess
<rdrop-exit>
tp, as long as you can switch optmizations off it's ok
<tabemann>
zeptoforth is a stupid compiler
<tabemann>
i.e. it compiles exactly what you tell it to
<rdrop-exit>
that's fine, any smarts should be layered on and optional
<tp>
rdrop-exit, I can by using a version that isnt optimised
<tp>
the Mecrisp-Stellaris binary isnt called with any switches
<rdrop-exit>
tp, I imagine there's words such as -peep +peep to switch any smarts off or on
<rdrop-exit>
(not necessarily those specific names)
<tp>
no
<tp>
I know all the base words by heart
<rdrop-exit>
oh well
<tp>
there may be secret wizard ways that arent documented or only in Gernam
<tabemann>
the mecrisp-stellaris code is maddening when it's all in german, because my german isn't that good
<rdrop-exit>
You haven't earned your Mecrisp Secret Decoder Ring (tm) yet
<tp>
they arent as bad as the C "-01" ? where loops get optimised away
<tp>
rdrop-exit, hahah, no and I probably never will, but frankly, I dont care
<rdrop-exit>
I never optimize control flow in my Forths
<tp>
all I want Mecrisp-Stellaris to do is help me make hardware
<rdrop-exit>
(except for tail call elimination)
<rdrop-exit>
No soup for you
<tp>
there is another final level of opts that Ive never used, this is done via a Word
<tp>
in my world, I have tons of speed, tons of memory, tons of peripherals, so I pretty much want for nothing
<tabemann>
the problem with TCE in Cortex-M is that farther bl calls are smaller than farther b calls, where one *needs* to create a literal and then feed it into blx
<tp>
for me this is the 'Golden Age" of microprocessors
<rdrop-exit>
I don't want an optimizer that does too much
<rdrop-exit>
just light peephole stuff + tail call
<tp>
in fact ... I read a embedded forum thread a couple of days ago where posters debated about the best way deal with a dead commericial eprom burner as the OP wanted to program a 2716. The debate was about Arduino or HAL, or Mbed etc
<tp>
I was stunned that someone would even post about the subjet as a Forth solution is a no brainer
<tp>
in the 70's we would make one ourselves with some logic chips and transistors, no mcu, and not think twice about it
<tp>
to me the only variables are 1) data input method, clone physical rom in socket to another 2716 ?, copy the data to a file ? burn new eprom from a file ? etc
<tp>
the actual technology is dead simple
<rdrop-exit>
people don't get simple anymore
<tp>
next I bet they will start building one with Arduino and running into 21V dc issues, or accurate delay time issues, or wether to use interrupts
<rdrop-exit>
they see the problem through the lenses of they're bloated tools
<tp>
or maybe problems with structures or pointers
<rdrop-exit>
*their
<tp>
they sure seem to
<tp>
Forth allows me to see the problem, then it FORCES me to understand what the problem actually is
<tp>
the code retreats into the background, it's not in my way
<rdrop-exit>
no premature abstraction
<tp>
if anything, the main issue I have with Forth is deciding which one of the many available methods to use
<tp>
because they all will work just fine
gravicappa has joined #forth
<tp>
it's like, I need a hole, should I use the shovel, or posthole digger ?
<rdrop-exit>
chrome-plated posthole digger
<tp>
I nearly followed up to the forum Post advising them it a simple solution just use Forth, then I remembered the typical C user disdain for Forth, and didn't bother.
<rdrop-exit>
they won't get it anyway
<tp>
hehe, Forth has uncountable solutions for every problem
<tp>
yeah, I'm (just) wise enough to know not to waste my time there
<rdrop-exit>
Don't forget it's a secret weapon
<tp>
I feel that in the end, when the binary hits the hardware, all solutions look much the same, wether it started out as C or Forth, etc
<tp>
it's the getting to the binary where the major differences, gains and traps lie
<rdrop-exit>
in theory you're right, but I'm sure there are plenty of bloated binaries out there
<tp>
as a tech, it's the getting to the binary that is my main area of interest
<tp>
youre definitely right
<tp>
If one uses the standard STM32 libs and Gcc for a blinky, the binary is about 30kB it's massive!
<rdrop-exit>
bbiab
<tabemann>
to me, Forth is essentially the love child of assembly and Lisp - it is almost as low level as assembly, but it is also simultaneously high level and has a powerful REPL and metaprogramming capabilities like Lisp
<tp>
then using various Opts it can get down to the same size as Forth, providing one knows the safe C opts to use
<tp>
tabemann, I agree
<tp>
tabemann, I see Forth as a layered top down design where all the Words at the top look a lot likeAssembly
<tp>
and as the Word list increases they look and are more HLL
<tp>
until finally the Words are the actual PDL
<tp>
on wash spin stop
<tp>
etc
<tabemann>
I've written Forth that looks very low level and Forth that looks very high level
<tabemann>
and yes, it's a progression from low level to high level typically
<tp>
thats typical of programmers for sure, but real world device Forth code behaves as I described
<tp>
without all the low level stuff the higher levels can't happen
<tp>
I tend to have two files, one is for all the low level stuff and is loaded first, the second is the high level stuff and is loaded last
<tp>
this is all orchestrated when I click the 'make' button in my gui editor
<tp>
I simply dont need to see the low level stuff after it's written and tested
<tabemann>
so in essence you've written something like a HAL layer that you can forget once it's working?
jsoft has joined #forth
dddddd has quit [Ping timeout: 248 seconds]
<tp>
good question
<tp>
but it's not a layer to me. To me it's just hardware 'configuration'
<tp>
once the low level hardware has been configured I can then move to the next level, designing Words to use the hardware
<tabemann>
I'm annoyed that I have run into the same problem that mecrisp-stellaris has
<tabemann>
you simply cannot allocate memory while compiling code in flash
<tp>
too much German ?
<tabemann>
the problem is this
<tp>
can you elaborate ?
<tabemann>
if you could allocate RAM in flash
<tabemann>
then flash would be pointing to arbitrary RAM floating in the middle of memory after rebooting
<tabemann>
the only real way to allocate memory from flash
<tabemann>
is to define offset pointers as constants in flash
<tabemann>
and to allot RAM by these offsets on bootup
<tp>
there is some trickery going on for sure
<tp>
ram has actual addresses, the same as flash
<tp>
I guess on could just allocate ram based on addresses from flash ?
<tp>
Mecrisp-Stellaris has a number of pointers that keep track of stuff like that
<tabemann>
I'm just going to use a word I call HERE!
<tabemann>
which sets the HERE pointer
<tabemann>
which can be used on bootup
<tabemann>
ALLOT could be used too
<tp>
i have a "here" word
<tabemann>
HERE! is for setting HERE
<tabemann>
to an absolute address
<tp>
I'm compiling in ram in this case
<tp>
here hex. 20002DE0 ok.
<tabemann>
actually, I've just got an idea!
<tp>
and now I've switched to 'compiletoflash'
<tp>
here hex. 0000CDB0 ok.
<tabemann>
I make a word that takes the form of : ALLOT-CONSTANT HERE SWAP ALLOT CONSTANT ;
<tabemann>
I did things slightly differently
<tabemann>
there are two HERE pointers, one for RAM and one for Flash, which are kept separate
<tabemann>
and there are a set of words that choose which to use based upon compilation mode
<tabemann>
but they're still underlyingly separate
<tabemann>
so you can still use HERE while compiling to flash
<tp>
i use HERE to compute the remaining ram and flash while developing user apps
<tp>
but it's result depends one the mode (Flash or Ram)
proteus-guy has joined #forth
<tabemann>
hey
proteus-dude has joined #forth
<MrMobius>
rdrop-exit, the thing is I'm doing a text replacement on some symbols and replacing them with [ array_base const_offset + ] literal which saves a lot of space
<MrMobius>
but then you cant use those symbols in immediate mode
proteus-dude has quit [Client Quit]
<MrMobius>
is there something clever you could replace the symbol with that would function like [ x y + ] literal in compile mode but x y + in immediate mode?
dave0 has quit [Quit: dave's not here]
<tabemann>
back
<tabemann>
: [+literal] STATE @ IF + POSTPONE LITERAL ELSE + THEN ; IMMEDIATE
<tabemann>
well
<tabemann>
maybe just
<tabemann>
: +lit STATE @ IF + POSTPONE LITERAL ELSE + THEN ; IMMEDIATE
<tabemann>
for short
<rdrop-exit>
MrMobius, does your Forth have constant folding? If it does you don't need to hand-optimize compilation with [ x y + ] literal
<rdrop-exit>
tabemann, that won't work
<tabemann>
yes it does
<tabemann>
1 2 + lit . 3 ok
<rdrop-exit>
there's nothing on the stack to add at compile-time
<tabemann>
: foo [ 1 2 ] +lit ; ok
<tabemann>
foo . 3 ok
<rdrop-exit>
sure if you use [ ... ] but that's what he's trying to avoid
<rdrop-exit>
if I understood correctly he wants the code to look the same whether he's interpreting or compiling
<tabemann>
and I don't see how you can do that
<tabemann>
unless
<rdrop-exit>
You'd have to make a fairly ugly prefix word
<tabemann>
yeah
<rdrop-exit>
which I wouldn't recommend in for this
<tabemann>
you'd have to make a word that parses x and y as its arguments after it
<rdrop-exit>
yup
<tabemann>
which seems like a bad way to do it
<rdrop-exit>
yup
<rdrop-exit>
I agree
<rdrop-exit>
Good uses of prefix words are fairly limited, exception handling and redirecting words, I don't think this is a good use case
<rdrop-exit>
(and defining words)
<rdrop-exit>
unless his Forth is running on a very small target, constant folding is the way to go I think
<rdrop-exit>
gotta go, kids are coming over, catch you all soon
rdrop-exit has quit [Quit: Lost terminal]
<MrMobius>
so basically something like : foo bar ; create foo2 bar ,
<MrMobius>
which becomes the equivalent of : foo [ base offset + ] literal ; create foo2 base offset + ,
<MrMobius>
and no onstant folding to answer rdrop-exit's question
<tp>
MrMobius, base offset + sounds like youre creating memory mapped Words ?
<MrMobius>
individual byte size variables
<MrMobius>
saves about 600 bytes doing it this way
<MrMobius>
which is significant on a 6502 system
<tp>
definitely
<tp>
I do a similar thing but it's processed externally from a XML file
<MrMobius>
how does that work?
<tp>
i have a big xml file of all the registers and I parse it with xlst into memory mapped words like so
<tp>
$40021000 constant RCC ( Reset and clock control )
<tp>
and so on for thousands of registers in some cases
<MrMobius>
neat
<tp>
it was one of the first things I did when I started using Forth because cortex-m mcus can have up to complex peripherals on the chip
<tp>
up to 97 peripherals
<tp>
and they can have lots of registers which have thousands of bitfields
<tp>
up until them all the Forth cortex-m users were just making their own unique memory mapped words so reusing their code was nearly impossible
<MrMobius>
I had some annoyances on a cortex m0 in C
<MrMobius>
different pins needed different code to do the same thing 0_0
<tp>
yeah, cortex-m0 has a couple of those
<tp>
i was also annoyed when I discovered those too
<tp>
I found them because my parser produced some different Words with the same memory mappings
<tp>
I can only imagine the C structure complexity top handle those cases
<tp>
-p
<MrMobius>
they are really efficient actually
<MrMobius>
if you give it a constant, it will shorten it down to exactly the code you need rather than including useless code you dont need for that pin
<tp>
one would hope so, but that leads me into a observation I have about C for embedded
<tp>
one can do the same kind of 'structure' in Forth thing that C does and at least one ex Forth user put a lot of effort into doing just that
<tp>
that was the now defunct 'geelabs' 'embello' thing
<tp>
but as a Forth user I find that Im usually only changing one config at a time, the last thing I'd ever want to have to do is configure every bitfield in a register at once
<tp>
which is what C users seem to do
<MrMobius>
like register=SOME_BIT|OTHER_BIT|THIRD_BIT; type thing?
<tp>
yeah, some of them are pretty horrible imho
<tp>
C attempts to make register configuration 'easier' I think, but there are so many permutations I think it's a lost cause trying to configure bitfields in groups
<tp>
Ive been working on various Forth processes to handle this since 2014 now
<MrMobius>
how would you write it then?
<tp>
it's no biggie with a 6502 I'm sure, but cortex-m is vastly complex
<tp>
Ive tried a few ways
<tp>
I think Ive only scratched the surface really, but the method Im using now is this one
<MrMobius>
0 SOME_BIT or OTHER_BIT or THIRD_BIT or register !
<tp>
I auto generate a word for every bitfield
<MrMobius>
hmm
<tp>
no, they have to be auto generated. there are far,far,far too many to do this stuff by hand