The simplest emulator in the world would be like this one:
unsigned char memory[65536];
int reg[8];
int main(void)
{
int pc = 0;
/* In this point you read something into memory */
while (1) {
instruction = memory[pc];
if (instruction == 0x76) break; /* HLT */
pc = (pc + 1) & 0xffff;
if ((instruction & 0xc0) == 0x40) /* Handle MOV r,r (opcodes 0x40-0x7f) */
reg[(instruction >> 3) & 7] = reg[instruction & 7];
}
return 0;
}
What it does? It simply reads each instruction from memory (PC is the Program Counter), and increments PC continuously limiting it to 16-bit.
It does a comparison for each possible instruction, for this example I only handled the most basic one of 8080 (MOV r,r) and HLT, but this is already 64 cases of the 256 possible!
Then I added iteratively chunks of opcodes to emulate and used language C macros to reduce the code size. For example, there is #define d(e) to join two 8-bit registers into a 16-bit value, and #define Q to read the accumulator.
In the end, to stay inside the size limit of the IOCCC, I removed the tree of 'if' statements and replaced it with a tree of trinary operators ?: (a way of doing 'if' inside an expression) and this is what the macros C and S does.
Automatic generation of code for Z80 is kind of hard because some operations are forced to use a few registers.
For example, ADD only works with A or HL (and IX or IY), and the code generator requires register shuffling or using the stack for saving temporary values.
My current approach is building a node tree for expressions, generating code by detecting common patterns, and if there isn't a pattern it goes the complicated but simple way. For example, for add:
right expr. / push hl / left expr. / pop de / add hl,de
Still pretty cool, and it's probably he first dedicate to and custom tailored to the Coleco! Come hang out with us BASIC folks over on discord if you use it https://discord.gg/jS6Jx8yJQP
We have a few BASIC creators (and of course users) over here including Marco who created ugBASIC.
Thanks! It was coded fast because I reused parts of my IntyBASIC compiler like the lexer, the expression analyzer, and the decision statements core (GOTO/GOSUB/WHILE/WEND etc). The first version of IntyBASIC took me almost two months to be ready.
Just try changing the first function definition in my source for tinyasm code to "struct label define_label(char name, int value)" and it will complain of error. Same with all my functions. I didn't had time for further dive looking for the error cause, so I just resorted to K&R.
I haven't tried to use the whole setup (with all headers etc) but if I put in my .c file the definition of struct and the ANSI C version of the definition of define_label,
struct label *define_label(char* name, int value)
{ ..
then C88 compiles without errors. On the page about the compiler the author of the page writes that he had to fix the standard libraries, but the compiler (C88) is definitely made to work with ANSI C "draft" which matches my experiment.
And I surely understand it was "good enough" a solution for you to do what you did.