A description of the AMC1

Wow, I forgot this site exists again! This time I won't post about dysphoria again! I will post about my first serious project that I actually could call complete, the AMC1!

Note: I did not put an <abbr> tag around AMC1 because it really doesn't stand for anything. It used to, but I forgot what it was… Either Amber's Magnificent Computer 1 or the Amber-Moxxie Computer 1 (Amber is my other name).

The AMC1 is a virtual machine, except as barebones as possible. No registers, no stack. Only an execution unit (which is a function) and memory (which is an array). I did actually build an accumulator machine version that I might post about soon, as well as an assembler but this is about the very first iteration. Programs are hardcoded arrays in the program itself. If you want to execute a new program, you gotta edit the arrays in source and recompile. The very very first iteration had no program loader to run multiple programs so it could only run one program at a time. However I hacked on a program loader that, with the help of you telling it exactly how many programs you want to run and the size of those programs, it will batch process those for you. I would like to point out that at this point I had basically no experience making VMs so you'll have to excuse the crudeness. The benefit is that the code is simple as fuck.

Speaking of code, let's walk through it! The project consists of two files, amc1.c and amc1.h. Please open these files and read them along with this article.

As you can see, not much is going on in amc1.h, we have the machine (struct amc1_t) which has its memory of 256 bytes, an instruction pointer (uint8_t ip) and a flag register (uint8_t flags) that never really gets used. The two flags that I bothered with are FLAG_LOOP and FLAG_TRAP but only the latter does something. Specifically, it simulates an OP_BRK between every program instruction. We also have the opcode enum, with comments and a function prototype

Moving along to amc1.c, we see a variety of things. First is the init_AMC1 function we saw earlier. Nothing much here, just setting stuff up. We then have the memory dump function which executes when OP_BRK dumps memory.

After that, we have a few helper functions, but first, I think I ought to explain how this machine works. Since we have no registers, we operate directly on the memory. All operands are actually pointers to the actual operands. That means that if I wanted to, say, add two numbers, the instruction in memory would look like OP_ADD ptr1 ptr2 ptr3. OP_ADD is the instruction that tells me to add, but the pointers are where the fun is. ptr1 points to the position in memory where operand 1 is. Same logic with ptr2. ptr3 tells you in which address to store the result. All unary/binary operations in the AMC1 work this way. Comparisons are similar. OP_JGZ ptr1 ptr2 would compare the operand pointed to by ptr1 with zero, and if it is greater than zero, it will jump to the address stored in the memory location pointed to by ptr2. OP_PRINT ptr1 would print the number stored at whatever ptr1 is pointing to, etc…

After the helper function and the decode function which actually executes all the opcodes, we have a function that loads a program into memory, some test programs and the main function