Wow, first users of Smaller C!Bender wrote: And gcc is also boring, so?
SmallerC
Smaller C (was: What does your OS look like?)
Smaller C (was: What does your OS look like?)
- Bender
- Member
- Posts: 449
- Joined: Wed Aug 21, 2013 3:53 am
- Libera.chat IRC: bender|
- Location: Asia, Singapore
Re: What does your OS look like? (Screen Shots..)
Hi,
I find SmallerC simple, although it may have certain limitations, but I wanted to choose the "other" way, cause I wanted something special.
The only problems I see is the "#define" preprocessor command which doesn't support parametrized macros.
Like:
Hope to see this fixed.
And btw Excellent work! Hope to see this compiler in the top lists along with being less bloated!
A lot of people here are interested in compiler development too. Your compiler is an invaluable resource.
-Bender
Welcome to ★☆OSDev.org ☆★alexfru wrote:Wow, first users of Smaller C!
I find SmallerC simple, although it may have certain limitations, but I wanted to choose the "other" way, cause I wanted something special.
The only problems I see is the "#define" preprocessor command which doesn't support parametrized macros.
Like:
Code: Select all
#define FUNC(VARS) DO_STUFF()
And btw Excellent work! Hope to see this compiler in the top lists along with being less bloated!
A lot of people here are interested in compiler development too. Your compiler is an invaluable resource.
-Bender
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
(R3X Runtime VM)(CHIP8 Interpreter OS)
Re: What does your OS look like? (Screen Shots..)
Until a proper preprocessor has been developed for Smaller C, your only options are:Bender wrote: I find SmallerC simple, although it may have certain limitations, but I wanted to choose the "other" way, cause I wanted something special.
The only problems I see is the "#define" preprocessor command which doesn't support parametrized macros.
Like:Hope to see this fixed.Code: Select all
#define FUNC(VARS) DO_STUFF()
— using a preprocessor from another compiler (gcc/djgpp and Open Watcom C/C++ will do)
— doing it manually as shown in file lb.c in functions printf(), vprintf() and __vsprintf__()
Re: What does your OS look like? (Screen Shots..)
I don't want to derail this thread, but allow me to ask a short question re SmallerC: would it be easy to retarget it to a different platform? I'm developing a CPU on an FPGA, and would love a C-compiler for it (the assembler is more or less finished).
JAL
JAL
Re: What does your OS look like? (Screen Shots..)
I suggest you to take a look at TinyCC: http://bellard.org/tcc/ -> http://repo.or.cz/w/tinycc.gitjal wrote:I don't want to derail this thread, but allow me to ask a short question re SmallerC: would it be easy to retarget it to a different platform? I'm developing a CPU on an FPGA, and would love a C-compiler for it (the assembler is more or less finished).
JAL
It seems to be easier to read and modify + better developed.
Re: What does your OS look like? (Screen Shots..)
A basic port (like the MIPS code generator of Smaller C) shouldn't be problematic. But ultimately it all depends on how primitive, complex or convoluted the target is and how far you're willing to go.jal wrote:I don't want to derail this thread, but allow me to ask a short question re SmallerC: would it be easy to retarget it to a different platform? I'm developing a CPU on an FPGA, and would love a C-compiler for it (the assembler is more or less finished).
Re: What does your OS look like? (Screen Shots..)
Currently it's a simple 16-bit CPU without multiplication and division, with separate address spaces for code and data.alexfru wrote:A basic port (like the MIPS code generator of Smaller C) shouldn't be problematic. But ultimately it all depends on how primitive, complex or convoluted the target is and how far you're willing to go.
JAL
Re: What does your OS look like? (Screen Shots..)
That is insufficiently descriptive.jal wrote:Currently it's a simple 16-bit CPU without multiplication and division, with separate address spaces for code and data.
The Z80 (or i8080/8085) could probably fit this description, except for the separate memory address spaces. It's got 16 bits of address, it can do 16-bit addition (and, by induction, left shifts of 16-bit values by one position), it's got no multiplication or division instructions. You could argue that its accumulator is 8-bit and most instructions are 8-bit, but one can synthesize everything out of those.
Let me illustrate the point a little more.
The x86 CPU has a rather large and complex instruction set. Most of its commonly used instructions can access their operands in registers and memory. The MIPS CPU, OTOH, has a very small general-purpose instruction set with very uniform/regular instructions that are mostly limited to register operands (I'm not mentioning immediate operands encoded inside instructions because these are supported by most CPUs and as such don't stand out).
So, while you can implement a very simple stack-based code generator for both with ease, further improving the MIPS code generator in terms of the number of instructions generated (and their size in bytes) per C operator will be noticeably harder than improving the x86 stack-based code generator because you'll need to start explicitly allocating registers to variables and intermediate results of expressions on the MIPS. On the x86 you can just do "add dword [MyVariable], MyConstant" and call it a day (until the day when you need something even better). On the MIPS, if you don't do much optimization, the equivalent operation will need at least 3 4-byte instructions (e.g. "lw $2, MyVariable($0)", "addiu $2, $2, MyConst", "sw $2, MyVariable($0)").
OTOH, x86 instructions routinely employ implicit operands in registers, e.g. in "shl ax, cl", "mov al, [bx]" you can't use arbitrary registers in place of "cl" and "bx". MIPS instructions are fairly regular in this regard and this isn't a problem. So, on the x86 you'll need quite a bit of code to handle special cases like these.
To be fair, the MIPS, like the ARM, these days has multiple instruction encodings. The new ones (e.g. MIPS16e) were designed to fix the problem of the original 4-byte instructions, which were simply taking too much space. The MIPS16e instructions aren't as powerful as the original ones and some of them also use implicit registers. If you want to support something like this, you need to handle special cases.
To sum it up, if the instructions are regular without implicit register operands (or with very few such operands), it's easy to write a code generator for them. If most of the general-purpose instructions can access memory operands, that's another helpful thing.
There are other variations on the theme, but this is the very first thing one needs to consider when writing a code generator.
Re: What does your OS look like? (Screen Shots..)
Well, I can elaborate a bit. It's a fairly standard RISC with minimal instructions. The CPU has 16 16-bit registers, of which one is hardwired to 0, and one is used as program counter. Instructions may have three registers as operand (rrr: destination, term1, term2), two registers and a 4-bit immediate value (rri), or a single register and a 16-bit immediate value. Instructions are add, sub, bit shift, all with both rrr and rri variants, and, or, xor (only rrr), load immediate (reg = 16-bit value), load from address register indirect with auto increment/decrement (reg1 = [reg2], reg2 += immediate value), load from address immediate indirect (reg = [addr]), store register indirect with auto inc/dec, and store immediate indirect. Also, there's a 1-byte opcode that causes the next instruction to be executed conditionally based on status flags.alexfru wrote:There are other variations on the theme, but this is the very first thing one needs to consider when writing a code generator.
JAL
Re: What does your OS look like? (Screen Shots..)
Looks like either you'll need a decent assembler for this CPU or you'll need to do some of its work in the code generator. For example, immediate operands that are shorter than 16 bits will need to be handled specially (or full-width operands w.r.t. to these short ones). The same applies to jumps/branches that use displacements of different widths. Short jumps are always painful to deal with. Not sure about "address" registers, if they are in any way special. On top of that, if the smallest memory operand is 16-bit, you'll have a bit of trouble implementing 8-bit chars and pointers to 8-bit chars, unless, of course, you abandon non-16-bit types altogether and make char=short=int=void*=void(*)()=16 bits=1 "C byte". Either way, if 8-bit chars aren't directly accessible, some serious work will be needed since the compiler is not designed to support such a platform (not that it can't be tweaked, of course, but it'll be many places, not one). Other than that it looks like you should be able to make a code generator similar to my MIPS CG relatively easily, but it'll likely be hard to make it generate more optimal code since only the load and store instructions can access data memory.jal wrote:Well, I can elaborate a bit. It's a fairly standard RISC with minimal instructions. ...
Re: What does your OS look like? (Screen Shots..)
I've written an assembler, so if the C compiler outputs asm that's fine (and even desirable).alexfru wrote:Looks like either you'll need a decent assembler for this CPU
No, there are just general purpose registers.Not sure about "address" registers, if they are in any way special.
That's indeed something I'd have to solve. I could have 16-bit chars, like having wchars and have the Unicode thing solved at the same time :). But I appreciate that's a bit of a problem for the compiler to deal with.On top of that, if the smallest memory operand is 16-bit, you'll have a bit of trouble implementing 8-bit chars and pointers to 8-bit chars, unless, of course, you abandon non-16-bit types altogether and make char=short=int=void*=void(*)()=16 bits=1 "C byte".
True, though given that there are 14 general purpose registers, it's probably possible to reserve a few for dedicated constructions (e.g. for loading memory operands in add or sub).Other than that it looks like you should be able to make a code generator similar to my MIPS CG relatively easily, but it'll likely be hard to make it generate more optimal code since only the load and store instructions can access data memory.
Thanks for the insight.
JAL
Re: Smaller C (was: What does your OS look like?)
Improvements/New things in Smaller C:
- bugfixes
- support initialization of multidimensional arrays
- support initialization of structures
- support initialization of structures and arrays inside functions
- support static inside functions
The compiler should now be much more usable.
- bugfixes
- support initialization of multidimensional arrays
- support initialization of structures
- support initialization of structures and arrays inside functions
- support static inside functions
The compiler should now be much more usable.
Re: Smaller C (was: What does your OS look like?)
I've uploaded binaries for DOS and most of the standard library.
Note: a few things are still missing from the library, most notably: <time.h> functionality, *scanf() functions.
Everyone's welcome to play with the compiler and report bugs.
How to install the .zip file downloaded from GitHub:
1. Create C:\SMLRC (any hard disk or name will do, but make the full path as short as possible) and copy into it the following subdirectories of the .zip file:
BIND
INCLUDE
LIB
TESTS
2. Include C:\SMLRC\BIND in the environment variable PATH
3. Don't forget to have NASM (2.10 is good) installed and also available via PATH
You should now be able to compile the following example from TESTS\hw.c:
I suggest to stick to the huge memory mode(l) as it supports 32-bit types such as long the functions that consume or return these types. In this mode(l) you can allocate all the available conventional memory via malloc() and you're not limited to objects smaller than 64KB.
The huge memory mode(l) is selected with the "-dosh" option, but you don't need to specify it explicitly when using a DOS version of smlrcc.
What else to know?
smlrcc can consume one or more of .c, .asm, .o or .a files and make an executable out of them.
If the command line is too long (over some 120 characters), you can put it into a file, say, mycmd.txt, and invoke smlrcc with @mycmd.txt (note the @ prefix) and it will extract the command line parameters from the file mycmd.txt. The linker (smlrl) supports this as well.
smlrcc supports the following useful options:
-c (compile only, don't link)
-S (compile to assembly only)
-v (verbose; show executed commands)
-map <mapfile> (produce the map file together with the binary)
You can compile your .c/.asm/.o files directly to a .a library file if you invoke smlrcc like so:
smlrcc [options] <file(s)> -c -o mylib.a
There's more but the documentation hasn't been updated for a while and so here I'm giving the most basic info only.
Enjoy.
Note: a few things are still missing from the library, most notably: <time.h> functionality, *scanf() functions.
Everyone's welcome to play with the compiler and report bugs.
How to install the .zip file downloaded from GitHub:
1. Create C:\SMLRC (any hard disk or name will do, but make the full path as short as possible) and copy into it the following subdirectories of the .zip file:
BIND
INCLUDE
LIB
TESTS
2. Include C:\SMLRC\BIND in the environment variable PATH
3. Don't forget to have NASM (2.10 is good) installed and also available via PATH
You should now be able to compile the following example from TESTS\hw.c:
Code: Select all
/*
How to compile for DOS (all mode(l)s: tiny/.COM, small/.EXE, huge/.EXE):
smlrcc -dost hw.c -o hwdt.com
smlrcc -doss hw.c -o hwds.exe
smlrcc -dosh hw.c -o hwdh.exe
*/
#include <stdio.h>
int main(void)
{
puts("Hello, World!");
return 0;
}
The huge memory mode(l) is selected with the "-dosh" option, but you don't need to specify it explicitly when using a DOS version of smlrcc.
What else to know?
smlrcc can consume one or more of .c, .asm, .o or .a files and make an executable out of them.
If the command line is too long (over some 120 characters), you can put it into a file, say, mycmd.txt, and invoke smlrcc with @mycmd.txt (note the @ prefix) and it will extract the command line parameters from the file mycmd.txt. The linker (smlrl) supports this as well.
smlrcc supports the following useful options:
-c (compile only, don't link)
-S (compile to assembly only)
-v (verbose; show executed commands)
-map <mapfile> (produce the map file together with the binary)
You can compile your .c/.asm/.o files directly to a .a library file if you invoke smlrcc like so:
smlrcc [options] <file(s)> -c -o mylib.a
There's more but the documentation hasn't been updated for a while and so here I'm giving the most basic info only.
Enjoy.
Re: Smaller C (was: What does your OS look like?)
I've just added support for Windows as both a host and a target platform.
This means that there are now executables and libraries for both DOS and Windows and you can develop on either platform for either platform.
The standard C library is practically complete (up to what the compiler supports in terms of the C language) and should be usable.
There have been some other changes and improvements in the meantime.
This means that there are now executables and libraries for both DOS and Windows and you can develop on either platform for either platform.
The standard C library is practically complete (up to what the compiler supports in terms of the C language) and should be usable.
There have been some other changes and improvements in the meantime.
Re: Smaller C (was: What does your OS look like?)
I've added Linux support (library and binaries).
So, finally, all 3 platforms (DOS, Windows and Linux) are the host and the target platforms.
Also, the documentation has been updated recently.
So, finally, all 3 platforms (DOS, Windows and Linux) are the host and the target platforms.
Also, the documentation has been updated recently.