mark4 changed the topic of #forth to: Forth Programming | do drop >in | logged by clog at http://bit.ly/91toWN backup at http://forthworks.com/forth/irc-logs/ | If you have two (or more) stacks and speak RPN then you're welcome here! | https://github.com/mark4th
eli_oat has joined #forth
eli_oat has quit [Quit: WeeChat 2.8]
<crc> N
<crc> neuro_sys: I build up from 30 primitives, but could drop some of them if I needed to
<crc> 15-18 would probably be my minimal set
* crc makes a note to test this sometime
boru` has joined #forth
boru has quit [Disconnected by services]
boru` is now known as boru
<tabemann> what is the point of using so few primitives, unless one is targeting something like an FPGA?
<tabemann> the reason why I ask is that even on very small systems, primitives hardcoded in assembly are likely to be denser than code generated by the forth compiler
<crc> I run on an emulated MISC architecture; my primitives correspond to the instruction set
<crc> I use inline assembly for some definitions, with the non-assembly versions as comments
<crc> I just prefer to keep the assembly part as small as possible as it's less readable than Forth
<Zarutian_HTC> tabemann: virtual machine implemented as an boolean sequential logic runnable ontop of smpc
<Zarutian_HTC> basically implementing a variation of the canonical dual stack machine from Philip Koopmans book Stack Machines the new wave
<Zarutian_HTC> and sometimes as a simple while switch construct in c, python, tcl, lua, javascript, and bash
<tabemann> I've implemented a very large set of primitives for zeptoforth because these primitives are denser than code generated by the code generator, and they can be copied verbatim into generated Forth code by the inliner
<tabemann> of course, if I wanted to save space, I'd use a VM with 256 primitives
<tabemann> running on top of the Cortex-M MCU
<tabemann> but that'd be slow
<tabemann> and I've specifically chosen to sacrifice space for speed
<Zarutian_HTC> I can imagine the slowdown on something like pipelined arm if you used fewer primitives
<tabemann> but yeah, if I wanted to write a really small forth I'd use token-threading, as then you can get 8 bits per primitive, which is way denser than what my native code generator/inliner can do
<Zarutian_HTC> I take it you would write it is assembly targetting some existing arch?
<tabemann> yes
<Zarutian_HTC> yeah, I needed some simple to implement arch that has the same code density as Forth, hence the few primitives and canonical dual stackmachine
<tabemann> to me the reason to use more, not less primitives, is that primitives can be really cheap if you do them right (e.g. they can take up one byte, so one gets 256 of them)
<Zarutian_HTC> and I mean implement as in specifying it in a bit extended BLIF or seq logic
<tabemann> the only reason I see to use fewer primitives is if A) one does not have enough space to implement them all or B) one is targeting something like an FPGA where implementing all that logic would be difficult
<Zarutian_HTC> precisely that I do not have the space to implement them
<Zarutian_HTC> space in the sense of number of and gates and such
<tabemann> FPGA's are the key area to me where it seems like minimizing the number of primitives would make sense
<tabemann> whereas on a MCU or like LIT 1 + will always take up more space than a 1+ primitive
<tabemann> and if you can have a good number of primitives one can have a number of then like LIT_-8, LIT_-4, LIT_-2, LIT_-1, LIT_0, LIT_1, LIT_2, LIT_4, LIT_8, and like
<tabemann> where the primitives encode small constants so a separate literal field is not needed
<Zarutian_HTC> I do have an 1+ primitive but mainly because it is easier to implement (LIT) as : (LIT) R> DUP 1+ >R @ ;
<Zarutian_HTC> (cell addressed memory, not byte addressed)
<Zarutian_HTC> and I define early such LIT words as you listed
<Zarutian_HTC> mainly because then code that use those literals takes up less memory space
<tabemann> exactly
gravicappa has joined #forth
<tabemann> okay, g'night
<Zarutian_HTC> gn
xek has quit [Remote host closed the connection]
<KipIngram> 1+ almost certainly should be a primitive - it usually requires just one machine instruction, and then you go straigt to the inner interpreter.
<KipIngram> neuro_sys: How few primitives you can get to depends on what your goal is. If you want the absolute minimum count no hold barred, then something in the 8-16 range is pretty easy to reach. But if you want to be able to say your system is anywhere near best performance you need more. Because if you have that minimum count the diddling around you have to do to implement things that could be extremely efficient
<KipIngram> primitives leaves you with a slow systen.
<KipIngram> I'm splitting that whole business into two layers in my latest system. I'm creating a set of assembly macros that I call "virtual instructions." And they are macros - a sequence of them generates consecutive code sequences. Then write primitives using those. And my general goal is to be able to have an implementation that will map out to optimum, or at least almost optimum, performance primitives on both
<KipIngram> x64 and ARM instruction sets.
<KipIngram> I'm guessing at this point, but I suspect I'll wind up with 50-60 virtual instructions.
<KipIngram> My system is heavy on primitives, because I have a lot of conditional return and conditional jump primitives. But only the virtual instructions will have to be re-done for a platform port.
Zarutian_HTC has quit [Read error: Connection reset by peer]
Zarutian_HTC has joined #forth
<KipIngram> You could imagine that instead of making those macros I made them themselves the primitives - then a lot of the things I'm calling primitives would be written threaded. I just push the "threading overhead" down one layer by inlining the virtual instructions.
<KipIngram> Most of the vi's are one-liners on x64, but the same vi might become a two-liner or something on ARM, since a lot of ARM instructions are register only.
<KipIngram> But the whole purpose was to get a "significant reduction" in the volume of things that need re-implementation on a port. From hundres of primitives down to dozens of vi's.
<KipIngram> So I have conditional return primitives, conditional two-level return primitives, and conditional "recurse" words (that mens jump to the beginning of the definition).
<KipIngram> And I also have variants of those that will retain one stack item more than the normal operation would. I give those a . prefix. So whereas = has two stack arguments and consumes them both, .= only consumes the one that' on TOS.
<KipIngram> So once you itemize that all out as a complete family it's a slew of primitves. But these things have gradually become my flow control words of choice.
<KipIngram> I code in a completely different way from how I did before implementing this idea.
f-a has joined #forth
xek has joined #forth
<proteus-guy> Great to see so many cool tech discussions in #forth! I think I should build a website that shows which handle is building which forth implementation just to keep track!
<f-a> haha
<KipIngram> :-)
f-a has quit [Read error: Connection reset by peer]
dys has joined #forth
<KipIngram> I decided this morning to write a Python script to generate the assembly source for my myriad conditional return / conditional recurse primitives. I think it will go together pretty easily and should completely rule out human error. There are like 70 or so of these things - I'd rather not do them by hand.
<KipIngram> I could reduce that number quite a lot if I were willing to use 2-3 words to accomplish the operations. But I sometimes have these managing very short tight little loops, so having them all atomic is a good way to keep performance up.
<KipIngram> For instance, I could have 0 <= ?; rather than 0<=; as its own primitive.
<veltas> Why not write a Forth script?
<KipIngram> I don't have one ready to do that. It'll get done faster in Python - I'm mostly already done with it.
<KipIngram> Forth isn't the only tool in the box.
<KipIngram> Python excells at text munging.
<KipIngram> excels
<nihilazo> that's true
<nihilazo> python is very good at that
<KipIngram> Cool - that's done and seems to work. I could have an error in it, of course. I'll save my source, delete the conditional primitives I'd already written, include this file, and see if it still runs.
<KipIngram> It might. I figure I've about an 80/20 chance of it working on the first go.
<veltas> I am trying to figure out how to build the core image of my C forth, I am trying to make it like the mark4 x4 experience of just run "make" and it builds, no weird dependencies
<nihilazo> is there any way to autoformat forth code
<nihilazo> my code is a mess of indentation and nonsense
<nihilazo> I guess it's harder than other languages because there isn't concrete syntax or formatting rules
<mark4> want no weird deps, do it in asm :)
<neuro_sys> Is this book a good one to read before implementing your own Forth? http://forth.org/OffeteStore/1010_SystemsGuideToFigForth.pdf
<neuro_sys> I already have some idea about how to do it, but I'd like to have a reference book just in case.
<mark4> well one of fig forths styles is to have every single part of your compiler in one source file
<mark4> so yea it might be good if you can make intelligent decisions against some of the things they advocae :)
Zarutian_HTC has quit [Ping timeout: 240 seconds]
<mark4> room mates dog is sick and shitting all over the livingroom floor. woke up yesterday to it and again today. cleaned it up yesterday because roommate was out
<mark4> and none of the vets are open grr
<veltas> There are usually out of hours vets
<veltas> In the UK you ring a vet and if they're closed they will provide an out-of-hours number
<veltas> On answering machine
<veltas> mark4: Manage to find an out of hours vet?
<mark4> no roomie is going to take dog to vet tomorrow
<veltas> Okay that's their choice I guess
<veltas> Should take them in if they're sick for over 24h though
<mark4> well he does not look sick or act sick he just wants to go out and poop every 2 or 3 hours and its icky stuff
<mark4> and i was taking him out every few hours last night till 4 am
<mark4> and then i slept and he couldnt help himself
<veltas> Poor guy
<mark4> not sure why he had to drip it all over the living room floor tho lol
<mark4> its not just in one spot its like a 2 inc splatter every square foot :)
mark4 has quit [Remote host closed the connection]
<KipIngram> Ok, those conditionsals all seem to be working.
<KipIngram> Didn't get my 80% - I had to troubleshoot it a bit.
<KipIngram> But it wasn't too bad.
<KipIngram> I've certainly not tested htem all. But the ones I've used to build what's functional so far must all be working, because, well, it functions. Correctly.
<KipIngram> Once I get to where I can load source from disk I'll write a test harness and test them exhaustively.
Zarutian_HTC has joined #forth
gravicappa has quit [Ping timeout: 260 seconds]
gravicappa has joined #forth
<veltas> I'm going to forget a ton of ALIGN's now I'm on a forth where that actually matters
dave0 has quit [Quit: dave's not here]
<veltas> Why did they make [COMPILE] obsolete?
<cmtptr> because [POSTPONE] is better
<cmtptr> it does what you want without you having to know at authorship time whether the word you're postponing is immediate or not
<veltas> But it's already required that you know whether a word has special compilation semantics or not
<veltas> POSTPONE is useful in that I can add semantics to compile a normal word, which [COMPILE] won't do
<veltas> Although it's easy to define a word to do it : [COMPILE,] ' COMPILE, ; IMMEDIATE
cantstanya has quit [Remote host closed the connection]
cantstanya has joined #forth
gravicappa has quit [Ping timeout: 268 seconds]
<veltas> What's a good name for a word returning the alignment size of cells?
<KipIngram> Anyone have or familiar with any sort of "conditional execute word" syntax? The thing would make the following word in the stream connditional.
<veltas> Something like IF1 CONDITIONAL-WORD
<veltas> ?
<KipIngram> Yeah. I was thinking maybe <condition>? So like <=? or !=? etc.
<veltas> I've not seen something like this but I don't see an argument against it
<KipIngram> I've tended away from "wordy" names as I've created things. I seem to prefer the more symbolic look.
<veltas> Personally I'd get no intuition from the naming you've suggested
<KipIngram> Well, it's not as intuitive as some of my others.
<veltas> Not that I'd get that from IF1 either, maybe IF: or ?:
<KipIngram> I find !=; or !=;; very intuitive.
<KipIngram> <cond>?: is kind of nice.
<veltas> I don't think I like contracting the condition into the name
<KipIngram> Anyway, I'm considering adding that. I seem to have almost every other conditional possibility I can thnk of.
<veltas> But if you want a lot of contractions then go for it
<KipIngram> Well, I understand that. And doing that runs up my primitive count severely.
<KipIngram> But it does buy some performance.
<KipIngram> But it's easy to get too performance hungry.
<KipIngram> In most real cases only a tiny bit of your code is responsible for the time consumption.
<KipIngram> Most of it is pretty irrelevant.
<KipIngram> I eventually want a profiling capability, so I can identify where the performance really counts.
<veltas> I think the reader should be able to learn all your control words, or at least guess what a control word is by seeing it
<KipIngram> Well, these feel that way to me. I actually agree with that. But these seem intuitive to me.
<veltas> Allowing for what they might read in a manual, tutorial or whatever. So I'm not saying it needs to be all 'standard' words
<KipIngram> I don't regard my "me" words (my nomenclature for recursing) as quite as "nice" as the conditional return words, but all the other things I could think of were a lot longer.
<veltas> Quite often one underestimates how confusing what makes sense to oneself is
<KipIngram> In the end I'm writing for me. :-)
<veltas> Well if you want to do that then there's no holding back
<KipIngram> I agree - it's easy to get your mind around something and then overlook its difficulty.
<KipIngram> I have conditional returns already - anything I could do with conditional execution I already can do that way. It just makes the word unusable without that conditional, and it's a bit lower performance, since you take on the call and the return.
<veltas> I find that in trying to make something for 'me' I try and think about others, because I write code *I* would like to use, which means that not being already intimately acquanted with it should not prevent understanding
<veltas> So I try and write code that I would like as the reader rather than the author
<KipIngram> Another thing that tempted me down the road of combininng that stuff into single words is, believe it or not, saving the space. My taste for having things look very tight on the page has gotten kind of strong.
<veltas> It doesn't save space if you have lots of words that aren't used more than once or twice :P
<KipIngram> No, I mean space on the printed page of source.
<KipIngram> The visual impact of what the code LOOKS like.
<veltas> Why? Are you trying to make it take less than 64 characters a line or something?
<KipIngram> I've had that problem over the years with C as well.
<KipIngram> I just hate code that seems to sprawl all over the page.
<KipIngram> I tend to write my C much like Forth - using "idiomatic phrases" and so on that I put all on one line.
<veltas> I like to write words over multiple lines
<KipIngram> Yes, me too.
<KipIngram> Which is one reason I wind up writing my whole system over multiple times.
<neuro_sys> I love tabular structuring, and Forth rubs me just in the right direction for that.
<neuro_sys> Not that I've been very attentive to that while learning/writing Forth code lately though.
<neuro_sys> I also love the full caps convention (again not doing it, because my caps lock is set to control because of Emacs).
<KipIngram> veltas: I do try to keep my definitions short. I do use the 64 value as a guideline there, but not because 64 is some magic number. It's just a number that's floating around that general vicinity. I do set my Forths up with block editors that show me 64 chars per line, and I try to never have multi-line definitions.
<KipIngram> My own feeling about "why" is just that I'm trying to take seriously the Forth philosophy of factor, factor, factor.
<KipIngram> I do find that it makes code easier for me to organize and grasp mentally.
<veltas> Good
<veltas> Size restraints tend to do that, but then when you're making contractions to save a space I think it's gone a little far :P
xek has quit [Ping timeout: 252 seconds]
<KipIngram> :-) Well, there's an objective benefit to those conditional returns. They're faster than the other way - no bones about it. So I think it's really a atter of the value I associate with knowing that it's "as fast as I can reasonably make it."
<KipIngram> I totally see your point of view too, though.
<KipIngram> Just last night I was noting how many primitives I'd eliminate if I just had the usual conditionals and then a boolean flag driven conditionl return.
<KipIngram> That would cut a pile of primitives.