Sunday, 29 December 2024

Show HN: WIP NandToTetris Emulator in pure C – logic gates to ALU to CPU to PC https://bit.ly/4fyRUIl

Show HN: WIP NandToTetris Emulator in pure C – logic gates to ALU to CPU to PC NandToTetris is a course which has you build a full computer from: Logic gates -> Chips -> RAM -> CPU -> Computer -> Assembler -> Compiler -> OS -> Tetris All this is done via software defined hardware emulation. I'm building an emulator for this entire stack in C. How is my approach different to other projects that seek to build emulators? - I start with a single software defined NAND gate in C. - EVERYTHING is built from this base chip - Rather than using existing programming utilities (boolean logic operators, bitwise logic operators etc) I build everything from this NAND gate. (Note: to bootstrap, I use boolean logic in the NAND chip only) - I don't use any boolean logic at all anywhere in the gates/chips (except NAND) - I build more and more base chips from the NAND gate, working my way up to an ALU, RAM, then the CPU. ------ Confused? Heres example code for my NAND gate: void nand_gate(Nand *nand) { nand->output.out = !(nand->input.a & nand->input.b); } From this gate I build a NOT gate (note, no boolean operators) void not_gate(Not * not ) { Nand nand = { .input.a = not ->input.in, .input.b = not ->input.in, }; nand_gate(&nand); not ->output.out = nand.output.out; } Then OR / AND / XOR / MUX / DMUX ..... and their 16 bit versions. Heres a more complex chip, a 16bit Mux-8-way chip /* * out = a if sel = 000 * b if sel = 001 * c if sel = 010 * d if sel = 011 * e if sel = 100 * f if sel = 101 * g if sel = 110 * h if sel = 111 */ void mux16_8_way_chip(Mux16_8_Way *mux16_8_way) { Mux16_4_Way mux16_4_way_chip_a, mux16_4_way_chip_b; Mux16 mux16_chip_c; // Mux a memcpy(mux16_4_way_chip_a.input.sel, mux16_8_way- >input.sel, sizeof(mux16_4_way_chip_a.input.sel)); memcpy(mux16_4_way_chip_a.input.a, mux16_8_way->input.a, sizeof(mux16_4_way_chip_a.input.a)); memcpy(mux16_4_way_chip_a.input.b, mux16_8_way->input.b, sizeof(mux16_4_way_chip_a.input.b)); memcpy(mux16_4_way_chip_a.input.c, mux16_8_way->input.c, sizeof(mux16_4_way_chip_a.input.c)); memcpy(mux16_4_way_chip_a.input.d, mux16_8_way->input.d, sizeof(mux16_4_way_chip_a.input.d)); mux16_4_way_chip(&mux16_4_way_chip_a); // Mux b memcpy(mux16_4_way_chip_b.input.sel, mux16_8_way->input.sel, sizeof(mux16_4_way_chip_b.input.sel)); memcpy(mux16_4_way_chip_b.input.a, mux16_8_way->input.e, sizeof(mux16_4_way_chip_b.input.a)); memcpy(mux16_4_way_chip_b.input.b, mux16_8_way->input.f, sizeof(mux16_4_way_chip_b.input.b)); memcpy(mux16_4_way_chip_b.input.c, mux16_8_way->input.g, sizeof(mux16_4_way_chip_b.input.c)); memcpy(mux16_4_way_chip_b.input.d, mux16_8_way->input.h, sizeof(mux16_4_way_chip_b.input.d)); mux16_4_way_chip(&mux16_4_way_chip_b); // Mux c mux16_chip_c.input.sel = mux16_8_way->input.sel[2]; memcpy(mux16_chip_c.input.a, mux16_4_way_chip_a.output.out, sizeof(mux16_chip_c.input.a)); memcpy(mux16_chip_c.input.b, mux16_4_way_chip_b.output.out, sizeof(mux16_chip_c.input.b)); mux16_chip(&mux16_chip_c); memcpy(mux16_8_way->output.out, mux16_chip_c.output.out, sizeof(mux16_8_way->output.out)); } ----- Progress: I have only started this project yesterday, so have completed 1 out of 7 hardware projects so far https://bit.ly/41V1amV December 30, 2024 at 02:05AM

No comments:

Post a Comment