Why not?
Why not?
Forth is the way it is mainly because Chuck Moore wants it that way. It's his preference. Tiny cores, typeless, hand-optimized to near metal, primitive VLSI tooling, 18-bit CPU's... nothing justified by scientific or engineering argument. All surpassed by other work in cost-benefit analysis. Nice write-up here by one person that delved deep into it to see good and bad of it:
http://yosefk.com/blog/my-history-with-forth-stack-machines....
It doesn't mean Forth is most convenient to write for any kind of problems, or that translator can easier optimize for Forth target... yet this at least is an opportunity to have a nicer language on the bare-bones level. Do you think it's a good enough thing?
One paper in my collection does that for IIRC Haskell to Forth by implementing a G-machine interpreter or compiler for a Forth CPU. It certainly can be done. Question is whether it's ideal vs a non-Forth CPU.
"At the same time you can have top performance with a concatenative, dense language."
I can do that with a Leon3 SPARC GPL'd with LISP or Forth extensions. It will be faster. Likewise, one can modify a simple, microcoded CPU to run Forth, Oberon, LISP, or whatever. Difference is that we're not tied to Forth's style in the process.
"yet this at least is an opportunity to have a nicer language on the bare-bones level. Do you think it's a good enough thing?"
If you have nothing else. Otherwise, no. I think, as I commented to avshalom, we can modify a flexible, simple RISC to have basic checks built-in. With microcode, you can raise abstraction to primitives of your choosing from expressions to stacks to heaps to pointer manipulation. Whatever you want.These can be composed of primitive instructions with checks enabled or disabled. You can then code in those with safe, highly-optimized primitives underneath making it fly in performance.
Further, as Intel does, you can always change underlying architecture to speed-up your model as you're leveraging microcode or ISA level. Last point, as my conversation with Alan Kay shows, is that modifying hardware to support OOP and late binding allows you productivity and code reduction of Smalltalk-style languages with still efficient, safe execution.
How much it would cost to you in terms of hardware - and maybe speed? - to have extensions which will have those nice features, especially if they are flexible, i.e. switchable? Would you need less gates than a Forth system?
That's not a fair question given Forth doesn't do crap compared to alternatives I'm pushing. More like "Does it use a reasonable number of gates for a commercial processor? For a MCU, do any schemes use a tiny number of gates to provide some protections vs existing MCU's?"
Answer to these are yes. As several people want links, here's a list of approaches ranging from safety to security, full to partial, MPU to MCU.
Two of the best for full safety are Hardbound and Watchdog, both from same group:
https://www.cis.upenn.edu/acg/papers/asplos08_hardbound.pdf
https://www.cs.rutgers.edu/~santosh.nagarakatte/papers/isca1...
One provides full spatial safety with other providing full memory safety with both having C compatibility. There are significant extra chip resources. Not a problem in a microprocessor, though, given the frivilous stuff takes up more space than this. The performance overhead is usually single-digit (under 5%) with it maxing out on 20% on Hardbound and 25% on Watchdog. For Watchdog, that's trading occasional 25% hit or buying a bit of extra CPU to get fully-compatible and safe C software. Great trade. HW experts could probably optimize it even further.
CHERI processor:
https://www.cl.cam.ac.uk/~swm11/research/papers/isca2014.pdf
CHERI processor adds capability-security to mix on MIPS processor. FreeBSD already ported. Uses 32% extra logic elements with 8% clock speed reduction and overhead similar to above designs. Recent papers added more protection, reduced some overheads, and so on. Strange enough, I used this one because the others have too much data to sift through quickly.
Sandia Secure Processor (SSP):
http://faculty.ist.unomaha.edu/winter/ShiftLab/Monarch_web/L...
For microcontrollers, Forth is a bad idea because it's typeless and dynamic. It's best to have strong typing plus static behavior so our current tooling can know exactly how it will behave. That naturally leads to things like Java. The system at jopdesign.com is just over 2,000 slices in FPGA. Idk if it has built-in safety checks or uses compiler's. However, this high-assurance CPU manages first-pass for 40,000 gates with full checks and verification. Plus can leverage Java tooling for automated unit tests, static analysis, dynamic analysis, design by contract... you name it. They even have a tool for converting regular Java to their tool.
Examples of ultra, lightweight schemes for MCU's:
http://www.icri-sc.org/fileadmin/user_upload/Group_TRUST/Pub...
Trustlite does isolation, attestation, and exception handling. It uses about 300 extra registers and 440 extra LUTS on a FPGA plus around 200 each per protected module. Tiny.
https://www.cs.utah.edu/~regehr/papers/plos06a.pdf
Works on 8-bit with TinyOS demonstration. Software method. Something like this could be hardware supported.
http://www.ece.umd.edu/~barua/simpson-CASES-2005.pdf
One for microcontrollers that averages 0.72% speed overhead (approx 10% max) and code size of 3.6%. Could be aided with HW.
http://read.seas.harvard.edu/~kohler/pubs/kumar07system.pdf
Another proven out on an ATmega with single-digit runtime effects and only a few thousands slices in MCU that's over 20,000 at start.
Note: You don't see much on 8-bit or 16-bit HW on my list as they're so constrained that a MPU or stack-overflow check is about all you can do. It's why I recommend against them most of the time. The likes of Infineon and Gemalto are stretching their capabilities far, though, in smartcard IC's with onboard crypto, MPU's, built-in checks, and usually a verified, safe OS or platform like MULTOS or JavaCard. One really just needs to use best tools and care they can on such platforms, though. 32-bit in 20,000-30,000 gate range is the lower bound so far on believable tech for assisted safety or security. I mean, you can use 8- or 16-bit with similar tech but your overall datapath and gates will be similar to 32-bit ones. Just get different tradeoffs in speed, code-size, addressing, and so on.
But a sample of the others could make for some good reading over semester break.
Thanks
https://news.ycombinator.com/item?id=11848132
I spent a lot of time on the other list. I spent at least 10 minutes for your question on variations of Forth, G-machine, and so on with Google coming up with nothing. Piece of crap search engine... I mean, just imagine one of the many G-machine compilers that have been described but whose end result are Forth operations implemented in hardware. I know seeing it is better but that's the gist. I make up for it hopefully with these two implementations of G-machine and a ML processor that I doubt you have:
http://digitalcommons.ohsu.edu/cgi/viewcontent.cgi?article=1...
https://news.ycombinator.com/item?id=10607730
Note: Use Wayback Machine at Archive.org if main PDF for SKI CPU doesn't load. Should be there.
No doubt. Many people might try to build on it for other reasons. Hence, my warning.
"A b5000-esque cpu would be much less straight forward"
Try crash-safe.org's main presentation on SAFE architecture. Narrow your focus to that one section on atomic groups. Mentally combine that with Burrough's most primitive checks. I'm talking code vs data check, pointer bounds check, pointer write-check to prevent modification, optionally stack overflow, and so on. Each one is a few lines of C code if you draw it out. I don't design HW but I've read enough of these to know there's close to zero performance and gate overhead in such simple checks. They typically run in parallel with CPU pipeline where it goes ahead with execution but doesn't actually write results unless gets a "1" (check succeeds) from parallel checkers. Simple, simple.
Academics with almost no team or budget typically start with highly-configurable, Leon3 CPU. They add the tags or checks into a few components. Synthesize for FPGA. Done. Then, compiler and/or OS modifications to make use of it. I've seen it done for RTEMS and Linux with small teams and mods. Cambridge's CHERI, with larger team, did whole capability-architecture that's C compatible and runs FreeBSD port. Changes that big have quite the performance implications, though, which is why I focus on primitive checks for interim or hobbyist use. ;)
I'm probably showing my ignorance, but I don't think anyone can convince me that in a perfect world software errors should be caught by dedicated hardware. Same with pushing software security issues to the HW.
SW needs a pottery barn rule, you broke it you pay for it. The HW is already too complicated as it is.
Software, even small stuff, has proven to be too complex to get right consistently except for the most, elite programmers. A safety net or safe by default makes more sense. It's more fundamental than that, though.
You see, certain languages in programming are closer to how we think and express our ideas as people. We find we get more productive as we abstract away from the machine. Yet, stuff close to machine is most efficient. Common machine designs were pretty arbitrary: alternatives existed with benefits. Market forces caused proliferation of specific, painful architectures.
So, the right thing seems to be to raise abstraction of underlying machine while modifying architecture to express safe or secure programs naturally. For instance, you don't want out of bounds pointers, overflowing stacks, or data treated as code. So, why does your CPU allow that in the first place all over memory and program code? Just foolish. Instead, design the CPU to include compiler-calculated bounds with pointers, to spot stack overflows in making, and to mark & treat differently code vs data. That's what Burroughs did and SAFE is doing.
Another is modular programming and OOP's takeover of modern programming. Our systems are broken down into modules with internal state, function calls operating on it, and function calls to other modules. We enforce separation between these states, expect some functions/data to stay private, and expect certain datatypes in function calls. Object-descriptor architectures divide hardware into objects with read/write/execute/access permissions enforced as CPU runs the program. Natural way to express such a system. Mapping OOP expressions & procedures onto a stack, heap, user/kernel MMU, and optionally some segments doesn't fit the use case at all. Alien to it actually.
So, the idea is to combine a language for efficient, productive, and safe-by-default expression of our intent as programmers with a CPU designed to efficiently run that plus provide low-cost checks as a safety net. That was Burroughs approach. An embedded version might be combination of Java subset with Java CPU's like jop-design.com or Sandia's Secure Processor (aka SSP or Score). Java CPU runs hardware ideal for language with some basic checks built-in that run at high speed. Language, type system, static analysis, compiler, and programmer do rest.
So, two different models. One is arbitrary machines designed for whatever Thompson or Moore preferred on minimal hardware they had with "just try harder" told to programmers. Other is carefully-designed, safe languages with CPU's built for them & checking their integrity. Option 2 makes more sense to me even if minority opinion. ;)
SW coming to HW saying "we need feature Y because our own SW process is so completely screwed up and out of control it takes an Einstein to do it right" I don't get.
Not making much sense. Part of this process you talk about is selecting tools that make job easier. Applies to CPU's as well as anything else. My research is taking it all the way down to how gates or analog circuits are done to max availability or integrity. Burroughs plus NonStop with correct by construction synthesis basically.
Except for cosmic rays flipping bits, well designed processors aren't inherently unsafe. People and the software they write are unsafe (guns don't kill people...). Why put any SW onus on HW where it will almost always be more expensive and less flexible?
Besides, empirical evidence is strongly against your statements about people's competence or bad analogies to guns. Empirical evidence, even for OpenBSD or Bernstein, show the best coders can't consistently make software work on tooling and architectures you seem to prefer. Whereas, average people using Rust and/or Java CPU's are producing software faster with few to no exploitable defects. And both can be targeted to under 10,000 gates (ARM is 30k+).
As the blog author points out, local variables are a huge issue on a stack machine because they lead to stack thrash. ANY stack manipulation must be seen as fundamentally inefficient, and they make Forth a naturally obfuscated write-only language IMO.
I understand complexity push-back, particularly in the processor / SW worlds where so much of it seems actually harmful, but the cult they've formed around Chuck Moore is kinda weird and it makes it hard for noobs to get a balanced picture of computing.
Forth routines are usually short so they don't need local variables.
> ANY stack manipulation must be seen as fundamentally inefficient
Why? I remember developing Forth code on a 6502 machine, and the code was just ten times slower than native assembler. That's not bad for a byte code interpreter. And the byte code is extremely compact which makes Forth very suitable for tiny systems.
Variables have to go somewhere. In a zero operand machine they go on the stack. Good luck finding them amidst all the confusing rolling, picking, duping, etc.
> Why?
Because the ALU is just laying there doing nothing while the stack is having it's spine manipulated (see above).
Of course you don't want to use roll or pick. That's tutorial-level knowledge that you shouldn't use them.
What you do when you see that coming is that you offload something to a global variable. The "something" is often the central topic of some part of the program, like a file handle for instance. So it makes sense to put it in a variable because it's needed in many places.
I think the opposite is true. Basic, Assembler and Forth were my first languages. Forth was the one that was the most powerful, and it showed me best on bare metal how a computer works.
As I already mentioned, in Forth you barely need variables. Everything happens on the stack. The rest is global.
Forth requires a radical shift in thinking about programming. You should read Leo Brodie's book "Thinking Forth".
http://thinking-forth.sourceforge.net/
> Good luck finding them amidst all the confusing rolling, picking, duping, etc.
Good Forth code style uses comments all the time. For instance:
( swap the two top values )
: myswap ( x y -- y x) <= x y is input, y x is output
swap ( y x ) ;
If you keep every Forth routine small then you can really have fun in Forth without local variables.By the way, I would never use Forth for big software. Forth is particularly powerful in tiny systems where every byte matters.
This is one issue I have with them. Real machines have local, fast storage you address directly with stores or functions operating on them. They have a remote storage, RAM, that you might work on directly with a CISC or move to local storage with many RISC's. In any case, the fundamental mechanisms are functions operating on individual data or function pointers. Best to map a high-level abstraction or low-level language directly to that. Whereas, a stack that flows this way, heap that flows that way... all this stuff isn't anything like how a computer fundamentally works. Except the stack-oriented architectures of course. :)
An alternative assembler might have variables, expressions, and function calls. Maybe differentiate between pointers and non pointers. Compile can handle (or help handle) mapping of that to non-stack machines. Looks a lot closer to Modula-2 or Oberon in the process once you consider ability to read, protect, and optimize the source code. Even though Wirth prefers stack machines for them. Another showed you could directly compile a subset to hardware:
One wonders why a company like GreenArray is trying to sell his designs. Must be a band of lunatics. A PhD paper from 2007 is certainly more serious than a company spending millions to get Moore's ideas on wafers.
Meanwhile, the products he hopes to displace are still selling well without the built-in drawbacks of his.