C/C++ compiler for softcore CPU - Page 1
Forum section: electronics / general

author: c64
author_rank: Frequent Contributor
timestamp: July 17, 2021, 02:18:05 am
content: Anyone knows a very simple softcore CPU (let's say < 500 LUT) which has C++ or C compiler for it?Also, let's suppose I design my own CPU. Is it hard to make a compiler for it?

author: ataradov
author_rank: Super Contributor
timestamp: July 17, 2021, 02:57:05 am
content: PicoRV32 is advertised as 750-2000 LUT. My very simple RISC-V core is about the same size (way less features, but also way easier to use) -https://github.com/ataradov/riscv.And you get a real compiler that you won't have to maintain.Making your own compiler from scratch is not trivial, but not impossible. But the only real reason to do it if you are explicitly interested in compiler creation. Otherwise it would be a huge pain.There are lots of C51 cores out there supported by SDCC. But SDCC is pretty terrible.

author: c64
author_rank: Frequent Contributor
timestamp: July 17, 2021, 03:54:27 am
content: I've seen people talking about using LLVM as a DIY compiler. Don't know if it's really easy to do or not

author: ataradov
author_rank: Super Contributor
timestamp: July 17, 2021, 04:09:19 am
content: It is not at all. It is a huge mess of C++. If you have never worked on compilers, but know your way around programming and not afraid of megabytes of poorly documented code, I'd estimate 1-2 months of full time work to add completely new architecture to LLVM.And then you have to maintain it. And LLVM is only the low level assembly. You would need to mess with Clang on top of that.Unless compilers are your primary interest, it is not worth it.TCC and SDCC are much easier to port, but they don't support C++, and even C support is spotty.But generally it is easier to get already supported core, as FPGA part is way less effort.

author: asmi
author_rank: Super Contributor
timestamp: July 17, 2021, 05:27:48 am
content: As someone who implemented C parsers as a lab exercise in University, I tend to agree with @ataradov that implementing your own complier is not worth the trouble unless you are specifically interested in compilers.

author: brucehoult
author_rank: Super Contributor
timestamp: July 17, 2021, 05:46:51 am
content: Quote from: ataradov on July 17, 2021, 04:09:19 amI think it's more like 1-2 months full time work to implement initial fairly complete but non-optimal support for a completely new ISA to LLVM *if* you are already rather experienced with LLVM.If you haven't worked with compilers and LLVM before then allow a year.

author: c64
author_rank: Frequent Contributor
timestamp: July 17, 2021, 06:06:05 am
content: OK I see LLVM is not an option then.If go with RISC-V and use PicoRV32 for example, is it possible to further decrease number of LUTs? For example, completely remove DIV and MUL

author: brucehoult
author_rank: Super Contributor
timestamp: July 17, 2021, 06:10:09 am
content: Quote from: c64 on July 17, 2021, 02:18:05 amThe number of LUTs depends on the FPGA architecture. Xilinx FPGAs with 6-LUTS need fewer of them than FPGAs with 4-input LUTs.If size if your overriding concern, not performance, then SeRV could be a good option.https://github.com/olofk/servOlof keep optimising the design. Here's a graph of SeRV LUT4 and FF use over time on iCE40:So that's now just over 200 FF and about 250 LUT4s. From memory Artix-7 is more like 190 LUTs.It's a bit-serial CPU, so it takes 32 clock cycles for most instructions, and 64 clocks for some such as branches and shifts. But it can clock pretty fast -- it won't slow down the rest of your design.SeRV just runs valid RV32I code. The effect of unimplemented opcodes is undefined.gcc/g++ will compile any C++ code you want for RV32I, no problems. Library routines for multiply, divide, 64 bit ints, floating point will get automatically linked in if you're crazy enough to use them.

author: brucehoult
author_rank: Super Contributor
timestamp: July 17, 2021, 06:13:35 am
content: Quote from: c64 on July 17, 2021, 06:06:05 amTake two minutes to read the README. There are tons of things you can include or leave out, or have smaller or faster versions.https://github.com/cliffordwolf/picorv32

author: KrudyZ
author_rank: Frequent Contributor
timestamp: July 17, 2021, 04:31:37 pm
content: The MICO8 from Lattice is very compact and has a C compiler.I've used it and it works as advertised and is fine for small projects, like communication port converters and simple machine control.Fits into even a small MACHX03.

author: laugensalm
author_rank: Regular Contributor
timestamp: July 17, 2021, 04:41:26 pm
content: You might also want to look at the ZPU architecture (which is a clever stack machine, however VHDL only). The GCC port is a little outdated, but works fine. It's just not the fastest beast around, depending on what you configure.Entry point:https://github.com/zylin/zpuI've hacked a pipelined version of it in MyHDL including ICE debugger, which spins as GHDL-powered cycle accurate virtual SoC, however this uses more like 700 LUTs. Included as VHDL output here:https://github.com/hackfin/MaSoCist,In terms of compactness and code density the ZPU is pretty optimal, I've managed to cram UDP-Stack, OS and remote control support in <32 kB.

author: langwadt
author_rank: Super Contributor
timestamp: July 17, 2021, 04:49:15 pm
content: a very old one and afair the articles explain how LCC was ported to it,http://www.pldworld.com/_hdl/2/_ip/-fpgacpu.org/xsoc/xr16.html

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 17, 2021, 06:17:27 pm
content: Quote from: c64 on July 17, 2021, 03:54:27 amIf you're thinking of designing your own original core, not compatible with any of the already supported targets, then uh... forget about it. Unless you have a LOT of free time.If you still want to do this, I'll suggest looking at TCC instead. Only supports C though, no C++ AFAIK. But it's a pretty good simple C compiler, still supporting C99 and a good chunk of C11. Still maintained too, not an old project. It's much, much easier to understand than GCC or LLVM. (https://repo.or.cz/w/tinycc.git)But I would first consider if designing your own ISA is really worth it, or if just implementing your soft core using a well-known ISA that has already support in major compilers wouldn't be MUCH easier. Of course RISC-V comes to mind, but you could consider other ISAs (such as MIPS, PowerPC or whatever else) - just be aware of possible licensing issues.

author: Morgan127
author_rank: Contributor
timestamp: July 17, 2021, 06:59:09 pm
content: You could have a look atInstant SoC.It compiles C++ to a soc with a Risc-V core. The C++ objects like UARTs etc will be both hardware (VHDL) and CPU code.It uses the standard gcc for Risc-V.Very easy to use. You only need to write C++.

author: brucehoult
author_rank: Super Contributor
timestamp: July 18, 2021, 12:36:44 am
content: Quote from: laugensalm on July 17, 2021, 04:41:26 pmSo I take it you have a working ZPU toolchain?I just checked out the toolchain but it failed in the autoconf stage on both my M1 Mac and Ubuntu 21.04 on RISC-V and I don't have an x86 Linux machine at present.I'd be very interested to see the objdump from compiling myhttps://hoult.org/primes.txtbenchmark -- at least for the countPrimes() function.

author: brucehoult
author_rank: Super Contributor
timestamp: July 18, 2021, 02:16:44 am
content: Quote from: SiliconWizard on July 17, 2021, 06:17:27 pmWhy design your own ISA?1) fun, education, challenge.OK, that's unarguable.2) so no one else can reverse-engineer or rip off your valuable code, compiled to your undocumented and possibly wacky ISA.Ooookay.3) because there aren't any existing good ISAs that you're allowed to use without getting sued and that fit your requirements.That used to be true, even not so long ago, but it's almost certainly not true now.There are obviously some fairly diverse ISAs such as the ZPU already mentioned, or the J1. Most of those seem to be both an ISA and an implementation, and it's probably not all that useful to make a different implementation. The same goes for ancient ISAs that you could probably get away with using such as 8080/z80, 6502, 8051. Also, OpenRISC.If things don't have a good C compiler -- preferably gcc or LLVM -- then that rules them out for many uses. Most of the 8 bit CPUs make a terrible target for high level languages -- it's possible, but both the code density and speed sucks relative to hand-written assembly language. Real large programs for them consist of hand-written assembly language for the speed-critical parts, plus an interpreter for a better designed ISA.Most old ISAs are also *full*. There's no room in the encoding left for custom instructions, so if you want to add something extra there's nowhere convenient to put it.It's not even as if the different ISAs are all that different to each other. The biggest difference is perhaps between stack-based ones and register-based ones. But even then they all have:- a way to load a constant literal value- a way to load a value from memory at a calculated address, or to store a calculated value there- arithmetic operations: add, subtract, and, or, xor, left shift, right shift (usually both logical and "arithmetic" provided)- a way to test a value against zero, or two values against each other, and choose different execution paths- a way to temporarily transfer execution to other place, remembering where it came from so it can return later, and to do this in a nested wayAfter this it's just pretty much meaningless variations in the number of registers, in the details of the binary encoding, and of possibly combining several of the above things into a single instruction. No new ISA since 1985 has made combined operations to any extent greater than adding together a register, a shifted register, and a constant to get an address for load/store (or to write back to a result register) -- and many don't do more than register plus constant.I think by now everyone here knows I'm a fan of RISC-V :-) :-)Why?- it's free to use- it's well supported by gcc and LLVM and by a rapidly growing number of libraries and OSes- it's got a lot of convenient encoding space reserved for custom instructions- it's very modular. Registers can be 32 or 64 bits. There can be 16 or 32 registers. gcc and llvm can target any combination, including down to compiling any C/C++ program to just 37 fixed-size 32 bit opcodes -- which is more like eight instruction types with simple variations: register to register arithmetic (10), register and 12 bit immediate arithmetic (9), conditional branch with 12 bit offset from PC (6), load (5) or store (3) with 12 bit offset from register, jump and link to address in register plus 12 bit offset (1), jump and link to PC + 20 bit offset shifted left by 1 (1), load 20 bit constant shifted left by 12 into a register and optionally add the PC (2). There are only four basic instruction formats.- There are a lot of different open source (and commercial) implementations with different size / speed / features trade-offs, with more every month. The smallest is around 200 LUTs plus 250 flip-flops. The biggest right now are Out-of-Order cores with per-cycle throughput comparable to Arm A72 or Intel Nehalem or maybe Sandy Bridge.

author: asmi
author_rank: Super Contributor
timestamp: July 18, 2021, 04:01:37 am
content: Quote from: brucehoult on July 18, 2021, 02:16:44 amYou forgot the most important one:- You work for a company which designs those cores.I'm also a big fan of RISC-V, and I also think most people here know it, but not because I work for someone who makes them

author: brucehoult
author_rank: Super Contributor
timestamp: July 18, 2021, 05:05:12 am
content: Quote from: asmi on July 18, 2021, 04:01:37 amI haven't worked for SiFive, or anyone else, for 17 months since February 2020. I'm taking a COVID sabbatical and general energy rejuvenation at a remote beach in the far north of New Zealand, driving 40 km into a small town once a week to visit the supermarket. There is no cell service here, but there is DSL.And my liking RISC-V led to working for SiFive, not the reverse.

author: ali_asadzadeh
author_rank: Super Contributor
timestamp: July 18, 2021, 06:18:38 am
content: Guys for educational purpose, do we have blog or article or book explaining the details how to do it for GCC or LLVM.

author: laugensalm
author_rank: Regular Contributor
timestamp: July 18, 2021, 06:28:29 am
content: Quote from: brucehoult on July 18, 2021, 12:36:44 amThe fastest way would be running the Docker container, if it's just about compiling a little snippet. You could run it 'online' as described in the masocist README (play-with-docker).If you're keen on getting it running on RISC-V, I could fork over the build rules as debian src package. It has to apply a few patches in order to build with recent GCC versions.

author: ataradov
author_rank: Super Contributor
timestamp: July 18, 2021, 06:40:39 am
content: Quote from: ali_asadzadeh on July 18, 2021, 06:18:38 amI'm not aware of any articles, but I went though that a little bit with GCC. And the best thing I could figure out is to take already supported platform that is close to your core (If it is a typical RISC, pick ARM or RISC-V). It helps to pick architecture that does not have good optimizations and a lot of core types. Then search for all the places where that architecture is mentioned and add corresponding chunks for your architecture. In the end you will have a compiler that can be compiled with support for your architecture, but still does the same exact thing that it did for the reference one. Then go and implement things for your architecture under the new defines and code paths. At the end you will have added the support for your architecture.This is extremely tedious, tiring, and not fun, but doable.

author: laugensalm
author_rank: Regular Contributor
timestamp: July 18, 2021, 06:58:41 am
content: Quote from: ali_asadzadeh on July 18, 2021, 06:18:38 amI've done some GCC/binutils hacking, you'll need to dig deep into the RTL 'description language', and read the source, mostly it's about taking a close example as template and start modifying/debugging (you need to be firm with gdb, too).However, when it comes to stack machines, GCC is sub optimal, it is just built around register architectures.Then, it's absolutely no fun and probably more work than the implementation to 'mainline' back to the FSF, plus you'll have to maintain it 'for free' for the next n years, or it gets removed from the distribution.LLVM is a little different, but not less complicated with the RTL. If I were to implement the next generation DSP, I'd go for LLVM.So, as feedback to the TO, the true innovation could lie in:- Write your own internal architecture, wrap a tiny microcode layer around it (so I've done with an extended ZPU implementation to just be able to rely on a working compiler).- Go for a totally different approach that generates working HDL and code, for example you might get inspired by this project (an 8 bit CPU including assembler in a jupyter notebook)https://github.com/pcornier/1pCPU

author: rstofer
author_rank: Super Contributor
timestamp: July 18, 2021, 01:34:55 pm
content: Quote from: ataradov on July 17, 2021, 02:57:05 amThat is a very nice project!

author: rstofer
author_rank: Super Contributor
timestamp: July 18, 2021, 01:55:22 pm
content: Quote from: laugensalm on July 17, 2021, 04:41:26 pmGiven a stack machine, it might be better to port the Pascal P4 project.http://pascal.hansotten.com/niklaus-wirth/px-compilers/p4-compiler/At one time, I was playing with taking the compiler output instructions and executing them directly in VHDL. No intermediate interpreter code as was used in UCSD Pascal for the Z80.For C, if I could understand the license terms, I might be inclined to use LCC since it is designed to be a retargetable C compiler. I have the book and it seems that the majority of the work is constrained to a small set of patterns used for code generation. In any event, personal use is unrestricted but it is not 'open source' or shareware.https://en.wikipedia.org/wiki/LCC_(compiler)The licensehttps://github.com/drh/lcc/blob/master/CPYRIGHT

author: laugensalm
author_rank: Regular Contributor
timestamp: July 18, 2021, 06:49:36 pm
content: I've also examined the LCC a while ago WRT to an interesting stack machine called X32, able to run LCCs intermediate bytecode.The killer criteria for me was some missing C99 support, in particular designated initializers, i.e.Code:struct gna{int bla;} s = { .bla = 1 }If the requirements are to work with legacy known working code, it's better to use a known working compiler...As you mention Niklaus Wirth: Although 'officially retired' for a long time, he wrote a very simple 'risc5' CPU and there's an Oberon community behind it, obviously ignored by all the RISC-V hype.

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 18, 2021, 06:56:08 pm
content: I mentioned TCC. Has any of you mentioning LCC taken a look at it?