├── .gitignore ├── test ├── components └── combinatorial │ ├── arithmetic │ ├── alu │ │ ├── alu.h │ │ ├── alu-types.h │ │ └── alu.c │ ├── add16 │ │ ├── add16.h │ │ ├── add16-types.h │ │ └── add16.c │ ├── inc16 │ │ ├── inc16.h │ │ ├── inc16-types.h │ │ └── inc16.c │ ├── full-adder │ │ ├── full-adder.h │ │ ├── full-adder-types.h │ │ └── full-adder.c │ └── half-adder │ │ ├── half-adder.h │ │ ├── half-adder-types.h │ │ └── half-adder.c │ ├── logic-gates │ ├── bit │ │ ├── or │ │ │ ├── or.h │ │ │ ├── or-types.h │ │ │ └── or.c │ │ ├── and │ │ │ ├── and.h │ │ │ ├── and-types.h │ │ │ └── and.c │ │ ├── not │ │ │ ├── not.h │ │ │ ├── not.c │ │ │ └── not-types.h │ │ ├── xor │ │ │ ├── xor.h │ │ │ ├── xor-types.h │ │ │ └── xor.c │ │ └── nand │ │ │ ├── nand.h │ │ │ ├── test-nand.h │ │ │ ├── nand.c │ │ │ ├── nand-types.h │ │ │ └── test-nand.c │ └── multi-bit │ │ ├── or16 │ │ ├── or16.h │ │ ├── or16.c │ │ └── or16-types.h │ │ ├── and16 │ │ ├── and16.h │ │ ├── and16.c │ │ └── and16-types.h │ │ ├── not16 │ │ ├── not16.h │ │ ├── not16.c │ │ └── not16-types.h │ │ └── or-8way │ │ ├── or-8way.h │ │ ├── or-8way-types.h │ │ └── or-8way.c │ └── multiplexers │ ├── bit │ ├── mux │ │ ├── mux.h │ │ ├── mux-types.h │ │ └── mux.c │ └── dmux │ │ ├── dmux.h │ │ ├── dmux-types.h │ │ └── dmux.c │ └── multi-bit │ ├── mux16 │ ├── mux16.h │ ├── mux16-types.h │ └── mux16.c │ ├── dmux-4way │ ├── dmux-4way.h │ ├── dmux-4way-types.h │ └── dmux-4way.c │ ├── dmux-8way │ ├── dmux-8way.h │ ├── dmux-8way-types.h │ └── dmux-8way.c │ ├── mux16-4way │ ├── mux16-4way.h │ ├── mux16-4way-types.h │ └── mux16-4way.c │ └── mux16-8way │ ├── mux16-8way.h │ ├── mux16-8way-types.h │ └── mux16-8way.c ├── .vscode ├── settings.json └── c_cpp_properties.json ├── utils ├── test-utils.h └── test-utils.c ├── types └── types.h ├── test.c ├── main.c ├── docs └── testing.md ├── makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | main -------------------------------------------------------------------------------- /test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/con-dog/hack_emulator_c/HEAD/test -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/alu/alu.h: -------------------------------------------------------------------------------- 1 | #ifndef ALU_H 2 | #define ALU_H 3 | 4 | #include "alu-types.h" 5 | 6 | void alu_chip(Alu *alu); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/or/or.h: -------------------------------------------------------------------------------- 1 | #ifndef OR_H 2 | #define OR_H 3 | 4 | #include "or-types.h" 5 | 6 | void or_gate(Or *or_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/and/and.h: -------------------------------------------------------------------------------- 1 | #ifndef AND_H 2 | #define AND_H 3 | 4 | #include "and-types.h" 5 | 6 | void and_gate(And *and_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/not/not.h: -------------------------------------------------------------------------------- 1 | #ifndef NOT_H 2 | #define NOT_H 3 | 4 | #include "not-types.h" 5 | 6 | void not_gate(Not *not_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/xor/xor.h: -------------------------------------------------------------------------------- 1 | #ifndef XOR_H 2 | #define XOR_H 3 | 4 | #include "xor-types.h" 5 | 6 | void xor_gate(Xor *xor_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/bit/mux/mux.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX_H 2 | #define MUX_H 3 | 4 | #include "mux-types.h" 5 | 6 | void mux_chip(Mux *mux_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/nand/nand.h: -------------------------------------------------------------------------------- 1 | #ifndef NAND_H 2 | #define NAND_H 3 | 4 | #include "nand-types.h" 5 | 6 | void nand_gate(Nand *nand_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/bit/dmux/dmux.h: -------------------------------------------------------------------------------- 1 | #ifndef DMUX_H 2 | #define DMUX_H 3 | 4 | #include "dmux-types.h" 5 | 6 | void dmux_chip(Dmux *dmux_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/add16/add16.h: -------------------------------------------------------------------------------- 1 | #ifndef ADD16_H 2 | #define ADD16_H 3 | 4 | #include "add16-types.h" 5 | 6 | void add16_chip(Add16 *add16_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/inc16/inc16.h: -------------------------------------------------------------------------------- 1 | #ifndef INC16_H 2 | #define INC16_H 3 | 4 | #include "inc16-types.h" 5 | 6 | void inc16_chip(Inc16 *inc16_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/or16/or16.h: -------------------------------------------------------------------------------- 1 | #ifndef OR16_H 2 | #define OR16_H 3 | 4 | #include "or16-types.h" 5 | 6 | void or16_gate(Or16 *or16_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/and16/and16.h: -------------------------------------------------------------------------------- 1 | #ifndef AND16_H 2 | #define AND16_H 3 | 4 | #include "and16-types.h" 5 | 6 | void and16_gate(And16 *and16_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/not16/not16.h: -------------------------------------------------------------------------------- 1 | #ifndef NOT16_H 2 | #define NOT16_H 3 | 4 | #include "not16-types.h" 5 | 6 | void not16_gate(Not16 *not16_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16/mux16.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX16_H 2 | #define MUX16_H 3 | 4 | #include "mux16-types.h" 5 | 6 | void mux16_chip(Mux16 *mux16_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/nand/test-nand.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_NAND_H 2 | #define TEST_NAND_H 3 | 4 | #include "test-utils.h" 5 | 6 | void test_nand(Test_Counter *counter); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/or-8way/or-8way.h: -------------------------------------------------------------------------------- 1 | #ifndef OR_8WAY_H 2 | #define OR_8WAY_H 3 | 4 | #include "or-8way-types.h" 5 | 6 | void or_8way_gate(Or_8way *or_8way_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/full-adder/full-adder.h: -------------------------------------------------------------------------------- 1 | #ifndef FULL_ADDER_H 2 | #define FULL_ADDER_H 3 | 4 | #include "full-adder-types.h" 5 | 6 | void full_adder_chip(Full_Adder *full_adder_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/half-adder/half-adder.h: -------------------------------------------------------------------------------- 1 | #ifndef HALF_ADDER_H 2 | #define HALF_ADDER_H 3 | 4 | #include "half-adder-types.h" 5 | 6 | void half_adder_chip(Half_Adder *half_adder_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/dmux-4way/dmux-4way.h: -------------------------------------------------------------------------------- 1 | #ifndef DMUX_4WAY_H 2 | #define DMUX_4WAY_H 3 | 4 | #include "dmux-4way-types.h" 5 | 6 | void dmux_4way_chip(Dmux_4way *dmux_4way_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/dmux-8way/dmux-8way.h: -------------------------------------------------------------------------------- 1 | #ifndef DMUX_8WAY_H 2 | #define DMUX_8WAY_H 3 | 4 | #include "dmux-8way-types.h" 5 | 6 | void dmux_8way_chip(Dmux_8way *dmux_8way_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16-4way/mux16-4way.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX16_4WAY_H 2 | #define MUX16_4WAY_H 3 | 4 | #include "mux16-4way-types.h" 5 | 6 | void mux16_4way_chip(Mux16_4way *mux16_4way_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16-8way/mux16-8way.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX16_8WAY_H 2 | #define MUX16_8WAY_H 3 | 4 | #include "mux16-8way-types.h" 5 | 6 | void mux16_8way_chip(Mux16_8way *mux16_8way_unit); 7 | 8 | #endif -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "stdlib.h": "c", 4 | "dmux.h": "c", 5 | "and.h": "c", 6 | "or-8-way.h": "c", 7 | "nand.h": "c", 8 | "mux16-8way.h": "c", 9 | "half-adder.h": "c", 10 | "add16.h": "c", 11 | "test-utils.h": "c" 12 | } 13 | } -------------------------------------------------------------------------------- /utils/test-utils.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_UTILS_H 2 | #define TEST_UTILS_H 3 | 4 | #include 5 | 6 | typedef struct Test_Counter 7 | { 8 | int tests_run; 9 | int tests_failed; 10 | } Test_Counter; 11 | 12 | void test_assert(bool condition, Test_Counter *counter, const char *format, ...); 13 | 14 | #endif -------------------------------------------------------------------------------- /types/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | #define BYTE_SIZE 8 4 | #define WORD_SIZE 16 5 | #define D_WORD_SIZE 32 6 | #define Q_WORD_SIZE 64 7 | 8 | #include 9 | 10 | typedef uint8_t Byte; 11 | typedef uint16_t Word; 12 | typedef uint32_t D_Word; 13 | typedef uint64_t Q_Word; 14 | 15 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/not/not.c: -------------------------------------------------------------------------------- 1 | #include "nand.h" 2 | #include "not.h" 3 | 4 | void not_gate(Not *not_unit) 5 | { 6 | Nand nand_unit = { 7 | .input.a = not_unit->input.in, 8 | .input.b = not_unit->input.in, 9 | }; 10 | nand_gate(&nand_unit); 11 | not_unit->output.out = nand_unit.output.out; 12 | } 13 | -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/nand/nand.c: -------------------------------------------------------------------------------- 1 | #include "nand.h" 2 | 3 | /* 4 | * | a | b | out | 5 | * --------------- 6 | * | 0 | 0 | 1 | 7 | * | 0 | 1 | 1 | 8 | * | 1 | 0 | 1 | 9 | * | 1 | 1 | 0 | 10 | */ 11 | void nand_gate(Nand *nand_unit) 12 | { 13 | nand_unit->output.out = !(nand_unit->input.a & nand_unit->input.b); 14 | } 15 | -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/not/not-types.h: -------------------------------------------------------------------------------- 1 | #ifndef NOT_TYPES_H 2 | #define NOT_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Not_Input 7 | { 8 | bool in; 9 | } Not_Input; 10 | 11 | typedef struct Not_Output 12 | { 13 | bool out; 14 | } Not_Output; 15 | 16 | typedef struct Not 17 | { 18 | Not_Input input; 19 | Not_Output output; 20 | } Not; 21 | 22 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/or/or-types.h: -------------------------------------------------------------------------------- 1 | #ifndef OR_TYPES_H 2 | #define OR_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Or_Input 7 | { 8 | bool a; 9 | bool b; 10 | } Or_Input; 11 | 12 | typedef struct Or_Output 13 | { 14 | bool out; 15 | } Or_Output; 16 | 17 | typedef struct Or 18 | { 19 | Or_Input input; 20 | Or_Output output; 21 | } Or; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/and/and-types.h: -------------------------------------------------------------------------------- 1 | #ifndef AND_TYPES_H 2 | #define AND_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct And_Input 7 | { 8 | bool a; 9 | bool b; 10 | } And_Input; 11 | 12 | typedef struct And_Output 13 | { 14 | bool out; 15 | } And_Output; 16 | 17 | typedef struct And 18 | { 19 | And_Input input; 20 | And_Output output; 21 | } And; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/xor/xor-types.h: -------------------------------------------------------------------------------- 1 | #ifndef XOR_TYPES_H 2 | #define XOR_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Xor_Input 7 | { 8 | bool a; 9 | bool b; 10 | } Xor_Input; 11 | 12 | typedef struct Xor_Output 13 | { 14 | bool out; 15 | } Xor_Output; 16 | 17 | typedef struct Xor 18 | { 19 | Xor_Input input; 20 | Xor_Output output; 21 | } Xor; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/nand/nand-types.h: -------------------------------------------------------------------------------- 1 | #ifndef NAND_TYPES_H 2 | #define NAND_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Nand_Input 7 | { 8 | bool a; 9 | bool b; 10 | } Nand_Input; 11 | 12 | typedef struct Nand_Output 13 | { 14 | bool out; 15 | } Nand_Output; 16 | 17 | typedef struct Nand 18 | { 19 | Nand_Input input; 20 | Nand_Output output; 21 | } Nand; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/not16/not16.c: -------------------------------------------------------------------------------- 1 | #include "not16.h" 2 | #include "not.h" 3 | #include "types.h" 4 | 5 | void not16_gate(Not16 *not16_unit) 6 | { 7 | Not not_units[WORD_SIZE]; 8 | for (int i = 0; i < WORD_SIZE; i++) 9 | { 10 | not_units[i].input.in = not16_unit->input.in[i]; 11 | not_gate(¬_units[i]); 12 | not16_unit->output.out[i] = not_units[i].output.out; 13 | } 14 | } -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/bit/mux/mux-types.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX_TYPES_H 2 | #define MUX_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Mux_Input 7 | { 8 | bool a; 9 | bool b; 10 | bool sel; 11 | } Mux_Input; 12 | 13 | typedef struct Mux_Output 14 | { 15 | bool out; 16 | } Mux_Output; 17 | 18 | typedef struct Mux 19 | { 20 | Mux_Input input; 21 | Mux_Output output; 22 | } Mux; 23 | 24 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/bit/dmux/dmux-types.h: -------------------------------------------------------------------------------- 1 | #ifndef DMUX_TYPES_H 2 | #define DMUX_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Dmux_Input 7 | { 8 | bool in; 9 | bool sel; 10 | } Dmux_Input; 11 | 12 | typedef struct Dmux_Output 13 | { 14 | bool a; 15 | bool b; 16 | } Dmux_Output; 17 | 18 | typedef struct Dmux 19 | { 20 | Dmux_Input input; 21 | Dmux_Output output; 22 | } Dmux; 23 | 24 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/inc16/inc16-types.h: -------------------------------------------------------------------------------- 1 | #ifndef INC16_TYPES_H 2 | #define INC16_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Inc16_Input 8 | { 9 | bool in[WORD_SIZE]; 10 | } Inc16_Input; 11 | 12 | typedef struct Inc16_Output 13 | { 14 | bool out[WORD_SIZE]; 15 | } Inc16_Output; 16 | 17 | typedef struct Inc16 18 | { 19 | Inc16_Input input; 20 | Inc16_Output output; 21 | } Inc16; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/or16/or16.c: -------------------------------------------------------------------------------- 1 | #include "or16.h" 2 | #include "or.h" 3 | #include "types.h" 4 | 5 | void or16_gate(Or16 *or16_unit) 6 | { 7 | Or or_units[WORD_SIZE]; 8 | for (int i = 0; i < WORD_SIZE; i++) 9 | { 10 | or_units[i].input.a = or16_unit->input.a[i]; 11 | or_units[i].input.b = or16_unit->input.b[i]; 12 | or_gate(&or_units[i]); 13 | or16_unit->output.out[i] = or_units[i].output.out; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/not16/not16-types.h: -------------------------------------------------------------------------------- 1 | #ifndef NOT16_TYPES_H 2 | #define NOT16_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Not16_Input 8 | { 9 | bool in[WORD_SIZE]; 10 | } Not16_Input; 11 | 12 | typedef struct Not16_Output 13 | { 14 | bool out[WORD_SIZE]; 15 | } Not16_Output; 16 | 17 | typedef struct Not16 18 | { 19 | Not16_Input input; 20 | Not16_Output output; 21 | } Not16; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/and/and.c: -------------------------------------------------------------------------------- 1 | #include "and.h" 2 | #include "nand.h" 3 | #include "not.h" 4 | 5 | void and_gate(And *and_unit) 6 | { 7 | Nand nand_unit = { 8 | .input.a = and_unit->input.a, 9 | .input.b = and_unit->input.b, 10 | }; 11 | nand_gate(&nand_unit); 12 | 13 | Not not_unit = { 14 | .input.in = nand_unit.output.out, 15 | }; 16 | not_gate(¬_unit); 17 | 18 | and_unit->output.out = not_unit.output.out; 19 | } 20 | -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/and16/and16.c: -------------------------------------------------------------------------------- 1 | #include "and16.h" 2 | #include "and.h" 3 | #include "types.h" 4 | 5 | void and16_gate(And16 *and16_unit) 6 | { 7 | And and_units[WORD_SIZE]; 8 | for (int i = 0; i < WORD_SIZE; i++) 9 | { 10 | and_units[i].input.a = and16_unit->input.a[i]; 11 | and_units[i].input.b = and16_unit->input.b[i]; 12 | and_gate(&and_units[i]); 13 | and16_unit->output.out[i] = and_units[i].output.out; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/add16/add16-types.h: -------------------------------------------------------------------------------- 1 | #ifndef ADD16_TYPES_H 2 | #define ADD16_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Add16_Input 8 | { 9 | bool a[WORD_SIZE]; 10 | bool b[WORD_SIZE]; 11 | } Add16_Input; 12 | 13 | typedef struct Add16_Output 14 | { 15 | bool out[WORD_SIZE]; 16 | } Add16_Output; 17 | 18 | typedef struct Add16 19 | { 20 | Add16_Input input; 21 | Add16_Output output; 22 | } Add16; 23 | 24 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/or-8way/or-8way-types.h: -------------------------------------------------------------------------------- 1 | #ifndef OR_8WAY_TYPES_H 2 | #define OR_8WAY_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Or_8way_Input 8 | { 9 | bool in[BYTE_SIZE]; 10 | } Or_8way_Input; 11 | 12 | typedef struct Or_8way_Output 13 | { 14 | bool out; 15 | } Or_8way_Output; 16 | 17 | typedef struct Or_8way 18 | { 19 | Or_8way_Input input; 20 | Or_8way_Output output; 21 | } Or_8way; 22 | 23 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/or16/or16-types.h: -------------------------------------------------------------------------------- 1 | #ifndef OR16_TYPES_H 2 | #define OR16_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Or16_Input 8 | { 9 | bool a[WORD_SIZE]; 10 | bool b[WORD_SIZE]; 11 | } Or16_Input; 12 | 13 | typedef struct Or16_Output 14 | { 15 | bool out[WORD_SIZE]; 16 | } Or16_Output; 17 | 18 | typedef struct Or16 19 | { 20 | Or16_Input input; 21 | Or16_Output output; 22 | } Or16; 23 | 24 | #endif -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/and16/and16-types.h: -------------------------------------------------------------------------------- 1 | #ifndef AND16_TYPES_H 2 | #define AND16_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct And16_Input 8 | { 9 | bool a[WORD_SIZE]; 10 | bool b[WORD_SIZE]; 11 | } And16_Input; 12 | 13 | typedef struct And16_Output 14 | { 15 | bool out[WORD_SIZE]; 16 | } And16_Output; 17 | 18 | typedef struct And16 19 | { 20 | And16_Input input; 21 | And16_Output output; 22 | } And16; 23 | 24 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/half-adder/half-adder-types.h: -------------------------------------------------------------------------------- 1 | #ifndef HALF_ADDER_TYPES_H 2 | #define HALF_ADDER_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Half_Adder_Input 7 | { 8 | bool a; 9 | bool b; 10 | } Half_Adder_Input; 11 | 12 | typedef struct Half_Adder_Output 13 | { 14 | bool sum; 15 | bool carry; 16 | } Half_Adder_Output; 17 | 18 | typedef struct Half_Adder 19 | { 20 | Half_Adder_Input input; 21 | Half_Adder_Output output; 22 | } Half_Adder; 23 | 24 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16/mux16-types.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX16_TYPES_H 2 | #define MUX16_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Mux16_Input 8 | { 9 | bool a[WORD_SIZE]; 10 | bool b[WORD_SIZE]; 11 | bool sel; 12 | } Mux16_Input; 13 | 14 | typedef struct Mux16_Output 15 | { 16 | bool out[WORD_SIZE]; 17 | } Mux16_Output; 18 | 19 | typedef struct Mux16 20 | { 21 | Mux16_Input input; 22 | Mux16_Output output; 23 | } Mux16; 24 | 25 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/full-adder/full-adder-types.h: -------------------------------------------------------------------------------- 1 | #ifndef FULL_ADDER_TYPES_H 2 | #define FULL_ADDER_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Full_Adder_Input 7 | { 8 | bool a; 9 | bool b; 10 | bool c; 11 | } Full_Adder_Input; 12 | 13 | typedef struct Full_Adder_Output 14 | { 15 | bool sum; 16 | bool carry; 17 | } Full_Adder_Output; 18 | 19 | typedef struct Full_Adder 20 | { 21 | Full_Adder_Input input; 22 | Full_Adder_Output output; 23 | } Full_Adder; 24 | 25 | #endif -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "test-utils.h" 4 | #include "test-nand.h" 5 | 6 | int main(void) 7 | { 8 | Test_Counter counter = { 9 | .tests_failed = 0, 10 | .tests_run = 0, 11 | }; 12 | 13 | /* 14 | * START: ADD ALL TESTS IN HERE 15 | */ 16 | test_nand(&counter); 17 | // NEXT TEST GOES HERE 18 | /* 19 | * END: ADD ALL TESTS IN HERE 20 | */ 21 | 22 | printf("\nTests run: \t%d\nTests failing: \t%d\n", counter.tests_run, counter.tests_failed); 23 | } -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/dmux-4way/dmux-4way-types.h: -------------------------------------------------------------------------------- 1 | #ifndef DMUX_4WAY_TYPES_H 2 | #define DMUX_4WAY_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Dmux_4way_Input 7 | { 8 | bool in; 9 | bool sel[2]; 10 | } Dmux_4way_Input; 11 | 12 | typedef struct Dmux_4way_Output 13 | { 14 | bool a; 15 | bool b; 16 | bool c; 17 | bool d; 18 | } Dmux_4way_Output; 19 | 20 | typedef struct Dmux_4way 21 | { 22 | Dmux_4way_Input input; 23 | Dmux_4way_Output output; 24 | } Dmux_4way; 25 | 26 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16/mux16.c: -------------------------------------------------------------------------------- 1 | #include "mux16.h" 2 | #include "mux.h" 3 | #include "types.h" 4 | 5 | void mux16_chip(Mux16 *mux16_unit) 6 | { 7 | Mux mux_units[WORD_SIZE]; 8 | for (int i = 0; i < WORD_SIZE; i++) 9 | { 10 | mux_units[i].input.a = mux16_unit->input.a[i]; 11 | mux_units[i].input.b = mux16_unit->input.b[i]; 12 | mux_units[i].input.sel = mux16_unit->input.sel; 13 | mux_chip(&mux_units[i]); 14 | mux16_unit->output.out[i] = mux_units[i].output.out; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/inc16/inc16.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "inc16.h" 3 | #include "add16.h" 4 | 5 | /** 6 | * 16-bit incrementer: 7 | * out = in + 1 8 | */ 9 | void inc16_chip(Inc16 *inc16_unit) 10 | { 11 | Add16 add16_unit = { 12 | .input.b = {[0] = 1, [1 ... WORD_SIZE - 1] = 0}, 13 | }; 14 | memcpy(add16_unit.input.a, inc16_unit->input.in, sizeof(add16_unit.input.a)); 15 | add16_chip(&add16_unit); 16 | memcpy(inc16_unit->output.out, add16_unit.output.out, sizeof(inc16_unit->output.out)); 17 | } 18 | -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/dmux-8way/dmux-8way-types.h: -------------------------------------------------------------------------------- 1 | #ifndef DMUX_8WAY_TYPES_H 2 | #define DMUX_8WAY_TYPES_H 3 | 4 | #include 5 | 6 | typedef struct Dmux_8way_Input 7 | { 8 | bool in; 9 | bool sel[3]; 10 | } Dmux_8way_Input; 11 | 12 | typedef struct Dmux_8way_Output 13 | { 14 | bool a; 15 | bool b; 16 | bool c; 17 | bool d; 18 | bool e; 19 | bool f; 20 | bool g; 21 | bool h; 22 | } Dmux_8way_Output; 23 | 24 | typedef struct Dmux_8way 25 | { 26 | Dmux_8way_Input input; 27 | Dmux_8way_Output output; 28 | } Dmux_8way; 29 | 30 | #endif -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/alu/alu-types.h: -------------------------------------------------------------------------------- 1 | #ifndef ALU_TYPES_H 2 | #define ALU_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Alu_Input 8 | { 9 | bool x[WORD_SIZE]; 10 | bool y[WORD_SIZE]; 11 | // 12 | bool zx; 13 | bool nx; 14 | // 15 | bool zy; 16 | bool ny; 17 | // 18 | bool f; 19 | bool no; 20 | } Alu_Input; 21 | 22 | typedef struct Alu_Output 23 | { 24 | bool out[WORD_SIZE]; 25 | bool zr; 26 | bool ng; 27 | } Alu_Output; 28 | 29 | typedef struct Alu 30 | { 31 | Alu_Input input; 32 | Alu_Output output; 33 | } Alu; 34 | 35 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16-4way/mux16-4way-types.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX16_4WAY_TYPES_H 2 | #define MUX16_4WAY_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Mux16_4way_Input 8 | { 9 | bool a[WORD_SIZE]; 10 | bool b[WORD_SIZE]; 11 | bool c[WORD_SIZE]; 12 | bool d[WORD_SIZE]; 13 | bool sel[2]; 14 | } Mux16_4way_Input; 15 | 16 | typedef struct Mux16_4way_Output 17 | { 18 | bool out[WORD_SIZE]; 19 | } Mux16_4way_Output; 20 | 21 | typedef struct Mux16_4way 22 | { 23 | Mux16_4way_Input input; 24 | Mux16_4way_Output output; 25 | } Mux16_4way; 26 | 27 | #endif -------------------------------------------------------------------------------- /utils/test-utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "test-utils.h" 4 | 5 | void test_assert(bool condition, Test_Counter *counter, const char *format, ...) 6 | { 7 | counter->tests_run++; 8 | 9 | // Handle variable arguments for formatted string 10 | va_list args; 11 | va_start(args, format); 12 | 13 | if (!condition) 14 | { 15 | counter->tests_failed++; 16 | printf("❌ FAIL: "); 17 | vprintf(format, args); 18 | printf("\n"); 19 | } 20 | else 21 | { 22 | printf("✅ PASS: "); 23 | vprintf(format, args); 24 | printf("\n"); 25 | } 26 | 27 | va_end(args); 28 | } -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/or/or.c: -------------------------------------------------------------------------------- 1 | #include "or.h" 2 | #include "not.h" 3 | #include "nand.h" 4 | 5 | void or_gate(Or *or_unit) 6 | { 7 | Not not_unit = { 8 | .input.in = or_unit->input.a, 9 | }; 10 | not_gate(¬_unit); 11 | 12 | Nand nand_unit_1 = { 13 | .input.a = not_unit.output.out, 14 | .input.b = or_unit->input.b, 15 | }; 16 | nand_gate(&nand_unit_1); 17 | 18 | Nand nand_unit_2 = { 19 | .input.a = not_unit.output.out, 20 | .input.b = nand_unit_1.output.out, 21 | }; 22 | nand_gate(&nand_unit_2); 23 | 24 | or_unit->output.out = nand_unit_2.output.out; 25 | } 26 | -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/half-adder/half-adder.c: -------------------------------------------------------------------------------- 1 | #include "half-adder.h" 2 | #include "and.h" 3 | #include "xor.h" 4 | 5 | void half_adder_chip(Half_Adder *half_adder_unit) 6 | { 7 | Xor xor_unit = { 8 | .input.a = half_adder_unit->input.a, 9 | .input.b = half_adder_unit->input.b, 10 | }; 11 | 12 | And and_unit = { 13 | .input.a = half_adder_unit->input.a, 14 | .input.b = half_adder_unit->input.b, 15 | }; 16 | 17 | xor_gate(&xor_unit); 18 | and_gate(&and_unit); 19 | half_adder_unit->output.sum = xor_unit.output.out; 20 | half_adder_unit->output.carry = and_unit.output.out; 21 | } 22 | -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/bit/dmux/dmux.c: -------------------------------------------------------------------------------- 1 | #include "dmux.h" 2 | #include "and.h" 3 | #include "not.h" 4 | 5 | void dmux_chip(Dmux *dmux_unit) 6 | { 7 | Not not_unit = { 8 | .input.in = dmux_unit->input.sel, 9 | }; 10 | not_gate(¬_unit); 11 | 12 | And and_unit_1 = { 13 | .input.a = dmux_unit->input.in, 14 | .input.b = not_unit.output.out, 15 | }; 16 | And and_unit_2 = { 17 | .input.a = dmux_unit->input.sel, 18 | .input.b = dmux_unit->input.in, 19 | }; 20 | 21 | and_gate(&and_unit_1); 22 | and_gate(&and_unit_2); 23 | dmux_unit->output.a = and_unit_1.output.out; 24 | dmux_unit->output.b = and_unit_2.output.out; 25 | } 26 | -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16-8way/mux16-8way-types.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX16_8WAY_TYPES_H 2 | #define MUX16_8WAY_TYPES_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct Mux16_8way_Input 8 | { 9 | bool a[WORD_SIZE]; 10 | bool b[WORD_SIZE]; 11 | bool c[WORD_SIZE]; 12 | bool d[WORD_SIZE]; 13 | bool e[WORD_SIZE]; 14 | bool f[WORD_SIZE]; 15 | bool g[WORD_SIZE]; 16 | bool h[WORD_SIZE]; 17 | bool sel[3]; 18 | } Mux16_8way_Input; 19 | 20 | typedef struct Mux16_8way_Output 21 | { 22 | bool out[WORD_SIZE]; 23 | } Mux16_8way_Output; 24 | 25 | typedef struct Mux16_8way 26 | { 27 | Mux16_8way_Input input; 28 | Mux16_8way_Output output; 29 | } Mux16_8way; 30 | 31 | #endif -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/bit/mux/mux.c: -------------------------------------------------------------------------------- 1 | #include "mux.h" 2 | #include "and.h" 3 | #include "not.h" 4 | #include "or.h" 5 | 6 | void mux_chip(Mux *mux_unit) 7 | { 8 | Not not_unit = { 9 | .input.in = mux_unit->input.sel}; 10 | not_gate(¬_unit); 11 | 12 | And and_unit_1 = { 13 | .input.a = mux_unit->input.a, 14 | .input.b = not_unit.output.out, 15 | }; 16 | and_gate(&and_unit_1); 17 | 18 | And and_unit_2 = { 19 | .input.a = mux_unit->input.sel, 20 | .input.b = mux_unit->input.b, 21 | }; 22 | and_gate(&and_unit_2); 23 | 24 | Or or_unit = { 25 | .input.a = and_unit_1.output.out, 26 | .input.b = and_unit_2.output.out, 27 | }; 28 | or_gate(&or_unit); 29 | 30 | mux_unit->output.out = or_unit.output.out; 31 | } 32 | -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/add16/add16.c: -------------------------------------------------------------------------------- 1 | #include "add16.h" 2 | #include "full-adder.h" 3 | 4 | /** 5 | * 16-bit adder: Adds two 16-bit two's complement values. 6 | * The most significant carry bit is ignored. 7 | */ 8 | void add16_chip(Add16 *add16_unit) 9 | { 10 | Full_Adder full_adder_units[WORD_SIZE]; 11 | for (int i = 0; i < WORD_SIZE; i++) 12 | { 13 | full_adder_units[i].input.a = add16_unit->input.a[i]; 14 | full_adder_units[i].input.b = add16_unit->input.b[i]; 15 | if (i == 0) 16 | { 17 | full_adder_units[i].input.c = 0; 18 | } 19 | else 20 | { 21 | full_adder_units[i].input.c = full_adder_units[i - 1].output.carry; 22 | } 23 | full_adder_chip(&full_adder_units[i]); 24 | add16_unit->output.out[i] = full_adder_units[i].output.sum; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/full-adder/full-adder.c: -------------------------------------------------------------------------------- 1 | #include "full-adder.h" 2 | #include "half-adder.h" 3 | #include "or.h" 4 | 5 | void full_adder_chip(Full_Adder *full_adder_unit) 6 | { 7 | Half_Adder half_adder_unit_1 = { 8 | .input.a = full_adder_unit->input.b, 9 | .input.b = full_adder_unit->input.c}; 10 | half_adder_chip(&half_adder_unit_1); 11 | 12 | Half_Adder half_adder_unit_2 = { 13 | .input.a = full_adder_unit->input.a, 14 | .input.b = half_adder_unit_1.output.sum, 15 | }; 16 | half_adder_chip(&half_adder_unit_2); 17 | 18 | Or or_unit = { 19 | .input.a = half_adder_unit_1.output.carry, 20 | .input.b = half_adder_unit_2.output.carry, 21 | }; 22 | or_gate(&or_unit); 23 | 24 | full_adder_unit->output.sum = half_adder_unit_2.output.sum; 25 | full_adder_unit->output.carry = or_unit.output.out; 26 | } 27 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "types/types.h" 3 | #include "components/combinatorial/arithmetic/add16/add16.h" 4 | #include "components/combinatorial/arithmetic/inc16/inc16.h" 5 | #include "components/combinatorial/arithmetic/full-adder/full-adder.h" 6 | #include "components/combinatorial/arithmetic/alu/alu.h" 7 | 8 | int main(void) 9 | { 10 | Alu alu = { 11 | .input.x = {0}, 12 | .input.y = {[0 ... WORD_SIZE - 1] = 1}, 13 | // 14 | .input.zx = 1, 15 | .input.nx = 1, 16 | // 17 | .input.zy = 1, 18 | .input.ny = 0, 19 | // 20 | .input.f = 1, 21 | .input.no = 0, 22 | }; 23 | alu_chip(&alu); 24 | 25 | for (int i = WORD_SIZE - 1; i >= 0; i--) 26 | { 27 | printf("%d", alu.output.out[i]); 28 | } 29 | printf("\n"); 30 | printf("%d\n", alu.output.zr); 31 | printf("%d\n", alu.output.ng); 32 | } -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/xor/xor.c: -------------------------------------------------------------------------------- 1 | #include "xor.h" 2 | #include "not.h" 3 | #include "and.h" 4 | #include "or.h" 5 | 6 | void xor_gate(Xor *xor_unit) 7 | { 8 | Not not_unit_1 = { 9 | .input.in = xor_unit->input.a}; 10 | not_gate(¬_unit_1); 11 | 12 | Not not_unit_2 = { 13 | .input.in = xor_unit->input.b}; 14 | not_gate(¬_unit_2); 15 | 16 | And and_unit_1 = { 17 | .input.a = not_unit_1.output.out, 18 | .input.b = xor_unit->input.b, 19 | }; 20 | and_gate(&and_unit_1); 21 | 22 | And and_unit_2 = { 23 | .input.a = xor_unit->input.a, 24 | .input.b = not_unit_2.output.out}; 25 | and_gate(&and_unit_2); 26 | 27 | Or or_unit = { 28 | .input.a = and_unit_1.output.out, 29 | .input.b = and_unit_2.output.out, 30 | }; 31 | or_gate(&or_unit); 32 | 33 | xor_unit->output.out = or_unit.output.out; 34 | } 35 | -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/bit/nand/test-nand.c: -------------------------------------------------------------------------------- 1 | // Truth Table 2 | /* 3 | * | a | b | out | 4 | * --------------- 5 | * | 0 | 0 | 1 | 6 | * | 0 | 1 | 1 | 7 | * | 1 | 0 | 1 | 8 | * | 1 | 1 | 0 | 9 | */ 10 | #include 11 | 12 | #include "test-nand.h" 13 | #include "nand.h" 14 | #include "test-utils.h" 15 | 16 | void test_nand(Test_Counter *counter) 17 | { 18 | // Truth table for NAND: expected outputs 19 | const int expected[4] = {1, 1, 1, 0}; // outputs for (0,0), (0,1), (1,0), (1,1) 20 | for (int i = 0; i < 4; i++) 21 | { 22 | Nand nand = { 23 | .input.a = (i >> 1) & 1, // Gets first bit (0011) 24 | .input.b = i & 1, // Gets second bit (0101) 25 | }; 26 | nand_gate(&nand); 27 | test_assert(nand.output.out == expected[i], counter, 28 | "NAND(%d,%d) should be %d", 29 | nand.input.a, 30 | nand.input.b, 31 | expected[i]); 32 | } 33 | } -------------------------------------------------------------------------------- /components/combinatorial/logic-gates/multi-bit/or-8way/or-8way.c: -------------------------------------------------------------------------------- 1 | #include "or-8way.h" 2 | #include "or.h" 3 | #include "types.h" 4 | 5 | void or_8way_gate(Or_8way *or_8way_unit) 6 | { 7 | Or or_units_block_a[BYTE_SIZE / 2]; 8 | for (int i = 0; i < BYTE_SIZE / 2; i++) 9 | { 10 | or_units_block_a[i].input.a = or_8way_unit->input.in[i]; 11 | or_units_block_a[i].input.b = or_8way_unit->input.in[i + BYTE_SIZE / 2]; 12 | or_gate(&or_units_block_a[i]); 13 | } 14 | 15 | Or or_units_block_b[BYTE_SIZE / 4]; 16 | for (int i = 0; i < BYTE_SIZE / 4; i++) 17 | { 18 | or_units_block_b[i].input.a = or_units_block_a[i].output.out; 19 | or_units_block_b[i].input.b = or_units_block_a[i + BYTE_SIZE / 4].output.out; 20 | or_gate(&or_units_block_b[i]); 21 | } 22 | 23 | Or or_unit = { 24 | .input.a = or_units_block_b[0].output.out, 25 | .input.b = or_units_block_b[1].output.out, 26 | }; 27 | or_gate(&or_unit); 28 | 29 | or_8way_unit->output.out = or_unit.output.out; 30 | } 31 | -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/dmux-4way/dmux-4way.c: -------------------------------------------------------------------------------- 1 | #include "dmux-4way.h" 2 | #include "dmux.h" 3 | 4 | /* 5 | * [a, b, c, d] = [in, 0, 0, 0] if sel = 00 6 | * [0, in, 0, 0] if sel = 01 7 | * [0, 0, in, 0] if sel = 10 8 | * [0, 0, 0, in] if sel = 11 9 | */ 10 | void dmux_4way_chip(Dmux_4way *dmux_4way_unit) 11 | { 12 | Dmux dmux_unit_1, dmux_unit_2, dmux_unit_3; 13 | 14 | dmux_unit_1.input.in = dmux_4way_unit->input.in; 15 | dmux_unit_1.input.sel = dmux_4way_unit->input.sel[1]; 16 | dmux_chip(&dmux_unit_1); 17 | 18 | dmux_unit_2.input.in = dmux_unit_1.output.a; 19 | dmux_unit_2.input.sel = dmux_4way_unit->input.sel[0]; 20 | dmux_chip(&dmux_unit_2); 21 | 22 | dmux_unit_3.input.in = dmux_unit_1.output.b; 23 | dmux_unit_3.input.sel = dmux_4way_unit->input.sel[0]; 24 | dmux_chip(&dmux_unit_3); 25 | 26 | dmux_4way_unit->output.a = dmux_unit_2.output.a; 27 | dmux_4way_unit->output.b = dmux_unit_2.output.b; 28 | dmux_4way_unit->output.c = dmux_unit_3.output.a; 29 | dmux_4way_unit->output.d = dmux_unit_3.output.b; 30 | } 31 | -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16-4way/mux16-4way.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mux16-4way.h" 3 | #include "mux16.h" 4 | #include "types.h" 5 | 6 | /* 7 | * out = a if sel = 00 8 | * b if sel = 01 9 | * c if sel = 10 10 | * d if sel = 11 11 | */ 12 | void mux16_4way_chip(Mux16_4way *mux16_4way_unit) 13 | { 14 | Mux16 mux16_unit_1, mux16_unit_2, mux16_unit_3; 15 | 16 | mux16_unit_1.input.sel = mux16_4way_unit->input.sel[0]; 17 | memcpy(mux16_unit_1.input.a, mux16_4way_unit->input.a, sizeof(mux16_4way_unit->input.a)); 18 | memcpy(mux16_unit_1.input.b, mux16_4way_unit->input.b, sizeof(mux16_4way_unit->input.b)); 19 | mux16_chip(&mux16_unit_1); 20 | 21 | mux16_unit_2.input.sel = mux16_4way_unit->input.sel[0]; 22 | memcpy(mux16_unit_2.input.a, mux16_4way_unit->input.c, sizeof(mux16_4way_unit->input.c)); 23 | memcpy(mux16_unit_2.input.b, mux16_4way_unit->input.d, sizeof(mux16_4way_unit->input.d)); 24 | mux16_chip(&mux16_unit_2); 25 | 26 | mux16_unit_3.input.sel = mux16_4way_unit->input.sel[1]; 27 | memcpy(mux16_unit_3.input.a, mux16_unit_1.output.out, sizeof(mux16_unit_3.input.a)); 28 | memcpy(mux16_unit_3.input.b, mux16_unit_2.output.out, sizeof(mux16_unit_3.input.b)); 29 | mux16_chip(&mux16_unit_3); 30 | 31 | memcpy(mux16_4way_unit->output.out, mux16_unit_3.output.out, sizeof(mux16_4way_unit->output.out)); 32 | } 33 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/utils", 8 | "${workspaceFolder}/components/combinatorial/logic-gates/bit/nand", 9 | "${workspaceFolder}/components/combinatorial/logic-gates/bit/not", 10 | "${workspaceFolder}/components/combinatorial/logic-gates/bit/and", 11 | "${workspaceFolder}/components/combinatorial/logic-gates/bit/or", 12 | "${workspaceFolder}/components/combinatorial/logic-gates/bit/xor", 13 | "${workspaceFolder}/components/combinatorial/logic-gates/multi-bit/not16", 14 | "${workspaceFolder}/components/combinatorial/logic-gates/multi-bit/and16", 15 | "${workspaceFolder}/components/combinatorial/logic-gates/multi-bit/or16", 16 | "${workspaceFolder}/components/combinatorial/logic-gates/multi-bit/or-8way", 17 | "${workspaceFolder}/components/combinatorial/multiplexers/bit/mux", 18 | "${workspaceFolder}/components/combinatorial/multiplexers/bit/dmux", 19 | "${workspaceFolder}/components/combinatorial/multiplexers/multi-bit/mux16", 20 | "${workspaceFolder}/components/combinatorial/multiplexers/multi-bit/mux16-4way", 21 | "${workspaceFolder}/components/combinatorial/multiplexers/multi-bit/mux16-8way", 22 | "${workspaceFolder}/components/combinatorial/multiplexers/multi-bit/dmux-4way", 23 | "${workspaceFolder}/components/combinatorial/multiplexers/multi-bit/dmux-8way", 24 | ], 25 | "defines": [], 26 | "macFrameworkPath": [], 27 | "compilerPath": "/usr/bin/gcc", 28 | "cStandard": "c17", 29 | "cppStandard": "c++17", 30 | "intelliSenseMode": "macos-gcc-x64" 31 | } 32 | ], 33 | "version": 4 34 | } -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/dmux-8way/dmux-8way.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dmux-8way.h" 3 | #include "dmux-4way.h" 4 | #include "dmux.h" 5 | 6 | /* 7 | * [a, b, c, d, e, f, g, h] = [in, 0, 0, 0, 0, 0, 0, 0] if sel = 000 8 | * [0, in, 0, 0, 0, 0, 0, 0] if sel = 001 9 | * [0, 0, in, 0, 0, 0, 0, 0] if sel = 010 10 | * [0, 0, 0, in, 0, 0, 0, 0] if sel = 011 11 | * [0, 0, 0, 0, in, 0, 0, 0] if sel = 100 12 | * [0, 0, 0, 0, 0, in, 0, 0] if sel = 101 13 | * [0, 0, 0, 0, 0, 0, in, 0] if sel = 110 14 | * [0, 0, 0, 0, 0, 0, 0, in] if sel = 111 15 | */ 16 | void dmux_8way_chip(Dmux_8way *dmux_8way_unit) 17 | { 18 | Dmux dmux_unit; 19 | Dmux_4way dmux_4way_unit_1, dmux_4way_unit_2; 20 | 21 | // dmux 22 | dmux_unit.input.in = dmux_8way_unit->input.in; 23 | dmux_unit.input.sel = dmux_8way_unit->input.sel[2]; 24 | dmux_chip(&dmux_unit); 25 | 26 | dmux_4way_unit_1.input.in = dmux_unit.output.a; 27 | memcpy(dmux_4way_unit_1.input.sel, dmux_8way_unit->input.sel, sizeof(dmux_4way_unit_1.input.sel)); 28 | dmux_4way_chip(&dmux_4way_unit_1); 29 | 30 | dmux_4way_unit_2.input.in = dmux_unit.output.b; 31 | memcpy(dmux_4way_unit_2.input.sel, dmux_8way_unit->input.sel, sizeof(dmux_4way_unit_2.input.sel)); 32 | dmux_4way_chip(&dmux_4way_unit_2); 33 | 34 | dmux_8way_unit->output.a = dmux_4way_unit_1.output.a; 35 | dmux_8way_unit->output.b = dmux_4way_unit_1.output.b; 36 | dmux_8way_unit->output.c = dmux_4way_unit_1.output.c; 37 | dmux_8way_unit->output.d = dmux_4way_unit_1.output.d; 38 | dmux_8way_unit->output.e = dmux_4way_unit_2.output.a; 39 | dmux_8way_unit->output.f = dmux_4way_unit_2.output.b; 40 | dmux_8way_unit->output.g = dmux_4way_unit_2.output.c; 41 | dmux_8way_unit->output.h = dmux_4way_unit_2.output.d; 42 | } 43 | -------------------------------------------------------------------------------- /components/combinatorial/multiplexers/multi-bit/mux16-8way/mux16-8way.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mux16-8way.h" 3 | #include "mux16-4way.h" 4 | #include "mux16.h" 5 | #include "types.h" 6 | 7 | /* 8 | * out = a if sel = 000 9 | * b if sel = 001 10 | * c if sel = 010 11 | * d if sel = 011 12 | * e if sel = 100 13 | * f if sel = 101 14 | * g if sel = 110 15 | * h if sel = 111 16 | */ 17 | void mux16_8way_chip(Mux16_8way *mux16_8way_unit) 18 | { 19 | Mux16_4way mux16_4way_unit_1, mux16_4way_unit_2; 20 | Mux16 mux16_unit; 21 | 22 | memcpy(mux16_4way_unit_1.input.sel, mux16_8way_unit->input.sel, sizeof(mux16_4way_unit_1.input.sel)); 23 | memcpy(mux16_4way_unit_1.input.a, mux16_8way_unit->input.a, sizeof(mux16_4way_unit_1.input.a)); 24 | memcpy(mux16_4way_unit_1.input.b, mux16_8way_unit->input.b, sizeof(mux16_4way_unit_1.input.b)); 25 | memcpy(mux16_4way_unit_1.input.c, mux16_8way_unit->input.c, sizeof(mux16_4way_unit_1.input.c)); 26 | memcpy(mux16_4way_unit_1.input.d, mux16_8way_unit->input.d, sizeof(mux16_4way_unit_1.input.d)); 27 | mux16_4way_chip(&mux16_4way_unit_1); 28 | 29 | memcpy(mux16_4way_unit_2.input.sel, mux16_8way_unit->input.sel, sizeof(mux16_4way_unit_2.input.sel)); 30 | memcpy(mux16_4way_unit_2.input.a, mux16_8way_unit->input.e, sizeof(mux16_4way_unit_2.input.a)); 31 | memcpy(mux16_4way_unit_2.input.b, mux16_8way_unit->input.f, sizeof(mux16_4way_unit_2.input.b)); 32 | memcpy(mux16_4way_unit_2.input.c, mux16_8way_unit->input.g, sizeof(mux16_4way_unit_2.input.c)); 33 | memcpy(mux16_4way_unit_2.input.d, mux16_8way_unit->input.h, sizeof(mux16_4way_unit_2.input.d)); 34 | mux16_4way_chip(&mux16_4way_unit_2); 35 | 36 | mux16_unit.input.sel = mux16_8way_unit->input.sel[2]; 37 | memcpy(mux16_unit.input.a, mux16_4way_unit_1.output.out, sizeof(mux16_unit.input.a)); 38 | memcpy(mux16_unit.input.b, mux16_4way_unit_2.output.out, sizeof(mux16_unit.input.b)); 39 | mux16_chip(&mux16_unit); 40 | 41 | memcpy(mux16_8way_unit->output.out, mux16_unit.output.out, sizeof(mux16_8way_unit->output.out)); 42 | } 43 | -------------------------------------------------------------------------------- /docs/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | ## Logic Tests 4 | ### Running Logic Tests 5 | From root of project, run the following commands to compile and run all tests: 6 | ```bash 7 | # Compile all tests 8 | make test 9 | # Run all tests 10 | ./test 11 | ``` 12 | 13 | ### Adding Logic Tests 14 | Inside each component directory, simply add a new file called `test-.h` and `test-.c` and write your tests in there. 15 | 16 | Heres an example of a test for the NAND gate: 17 | ```c 18 | // Truth Table 19 | /* 20 | * | a | b | out | 21 | * --------------- 22 | * | 0 | 0 | 1 | 23 | * | 0 | 1 | 1 | 24 | * | 1 | 0 | 1 | 25 | * | 1 | 1 | 0 | 26 | */ 27 | #include 28 | 29 | #include "test-nand.h" 30 | #include "nand.h" 31 | #include "test-utils.h" 32 | 33 | void test_nand(Test_Counter *counter) 34 | { 35 | // Truth table for NAND: expected outputs 36 | const int expected[4] = {1, 1, 1, 0}; // outputs for (0,0), (0,1), (1,0), (1,1) 37 | for (int i = 0; i < 4; i++) 38 | { 39 | Nand nand = { 40 | .input.a = (i >> 1) & 1, // Gets first bit (0011) 41 | .input.b = i & 1, // Gets second bit (0101) 42 | }; 43 | nand_gate(&nand); 44 | test_assert(nand.output.out == expected[i], counter, 45 | "NAND(%d,%d) should be %d", 46 | nand.input.a, 47 | nand.input.b, 48 | expected[i]); 49 | } 50 | } 51 | ``` 52 | 53 | The next step to get tests running is to add the test to the `test.c` file in the root of the project. This file is used to compile all tests and run them. Simply add the test function to the `main` function in `test.c` like so: 54 | ```c 55 | int main(void) 56 | { 57 | Test_Counter counter = { 58 | .tests_failed = 0, 59 | .tests_run = 0, 60 | }; 61 | 62 | /* 63 | * START: ADD ALL TESTS IN HERE 64 | */ 65 | test_nand(&counter); 66 | // NEXT TEST GOES HERE 67 | /* 68 | * END: ADD ALL TESTS IN HERE 69 | */ 70 | 71 | printf("\nTests run: \t%d\nTests failing: \t%d\n", counter.tests_run, counter.tests_failed); 72 | } 73 | ``` -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Compiler and flags 2 | CC = gcc 3 | CFLAGS = -Wall -Wextra 4 | 5 | # Directory structure 6 | COMPONENTS_DIR = components 7 | COMB_DIR = $(COMPONENTS_DIR)/combinatorial 8 | SEQ_DIR = $(COMPONENTS_DIR)/sequential 9 | TYPES_DIR = types 10 | UTILS_DIR = utils 11 | 12 | # Logic gates directories 13 | LOGIC_BIT_DIR = $(COMB_DIR)/logic-gates/bit 14 | LOGIC_MULTI_DIR = $(COMB_DIR)/logic-gates/multi-bit 15 | MUX_BIT_DIR = $(COMB_DIR)/multiplexers/bit 16 | MUX_MULTI_DIR = $(COMB_DIR)/multiplexers/multi-bit 17 | ARITH_DIR = $(COMB_DIR)/arithmetic 18 | 19 | # Include paths 20 | INCLUDES = \ 21 | -I$(LOGIC_BIT_DIR)/nand \ 22 | -I$(LOGIC_BIT_DIR)/not \ 23 | -I$(LOGIC_BIT_DIR)/and \ 24 | -I$(LOGIC_BIT_DIR)/or \ 25 | -I$(LOGIC_BIT_DIR)/xor \ 26 | \ 27 | -I$(LOGIC_MULTI_DIR)/not16 \ 28 | -I$(LOGIC_MULTI_DIR)/and16 \ 29 | -I$(LOGIC_MULTI_DIR)/or16 \ 30 | -I$(LOGIC_MULTI_DIR)/or-8way \ 31 | \ 32 | -I$(MUX_BIT_DIR)/mux \ 33 | -I$(MUX_BIT_DIR)/dmux \ 34 | \ 35 | -I$(MUX_MULTI_DIR)/mux16 \ 36 | -I$(MUX_MULTI_DIR)/mux16-4way \ 37 | -I$(MUX_MULTI_DIR)/mux16-8way \ 38 | -I$(MUX_MULTI_DIR)/dmux-4way \ 39 | -I$(MUX_MULTI_DIR)/dmux-8way \ 40 | \ 41 | -I$(ARITH_DIR)/half-adder \ 42 | -I$(ARITH_DIR)/full-adder \ 43 | -I$(ARITH_DIR)/add16 \ 44 | -I$(ARITH_DIR)/inc16 \ 45 | -I$(ARITH_DIR)/alu \ 46 | \ 47 | -I$(TYPES_DIR) \ 48 | \ 49 | -I$(UTILS_DIR) 50 | 51 | 52 | # Source files 53 | LOGIC_BIT_SRC = $(wildcard $(LOGIC_BIT_DIR)/*/*.c) 54 | LOGIC_MULTI_SRC = $(wildcard $(LOGIC_MULTI_DIR)/*/*.c) 55 | MUX_BIT_SRC = $(wildcard $(MUX_BIT_DIR)/*/*.c) 56 | MUX_MULTI_SRC = $(wildcard $(MUX_MULTI_DIR)/*/*.c) 57 | ARITH_SRC = $(wildcard $(ARITH_DIR)/*/*.c) 58 | SEQ_SRC = $(wildcard $(SEQ_DIR)/*/*.c) 59 | UTILS_SRC = $(wildcard $(UTILS_DIR)/*.c) 60 | MAIN_SRC = main.c 61 | TEST_SRC = test.c 62 | 63 | # All source files 64 | SRC = $(MAIN_SRC) $(UTILS_SRC) $(LOGIC_BIT_SRC) $(LOGIC_MULTI_SRC) $(MUX_BIT_SRC) $(MUX_MULTI_SRC) $(ARITH_SRC) $(SEQ_SRC) 65 | 66 | # Object files 67 | OBJ = $(SRC:.c=.o) 68 | 69 | # Test object files (similar to OBJ but with tests.c instead of main.c) 70 | TEST_OBJ = $(filter-out main.o, $(OBJ)) $(TEST_SRC:.c=.o) 71 | 72 | # Main target 73 | TARGET = main 74 | TEST_TARGET = test 75 | 76 | # Targets 77 | all: $(TARGET) 78 | 79 | $(TARGET): $(OBJ) 80 | $(CC) $(OBJ) -o $@ 81 | 82 | test: $(TEST_TARGET) 83 | 84 | $(TEST_TARGET): $(TEST_OBJ) 85 | $(CC) $(TEST_OBJ) -o $@ 86 | 87 | %.o: %.c 88 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 89 | 90 | clean: 91 | rm -f $(TARGET) $(TEST_TARGET) $(OBJ) $(TEST_SRC:.c=.o) 92 | 93 | rebuild: clean all 94 | 95 | .PHONY: all clean rebuild test -------------------------------------------------------------------------------- /components/combinatorial/arithmetic/alu/alu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "alu.h" 3 | #include "mux16.h" 4 | #include "not16.h" 5 | #include "and16.h" 6 | #include "add16.h" 7 | #include "or-8way.h" 8 | #include "or.h" 9 | #include "not.h" 10 | #include "types.h" 11 | 12 | /** 13 | * ALU (Arithmetic Logic Unit): 14 | * Computes out = one of the following functions: 15 | * 0, 1, -1, 16 | * x, y, !x, !y, -x, -y, 17 | * x + 1, y + 1, x - 1, y - 1, 18 | * x + y, x - y, y - x, 19 | * x & y, x | y 20 | * on the 16-bit inputs x, y, 21 | * according to the input bits zx, nx, zy, ny, f, no. 22 | * In addition, computes the two output bits: 23 | * if (out == 0) zr = 1, else zr = 0 24 | * if (out < 0) ng = 1, else ng = 0 25 | */ 26 | // Implementation: Manipulates the x and y inputs 27 | // and operates on the resulting values, as follows: 28 | // if (zx == 1) sets x = 0 // 16-bit constant 29 | // if (nx == 1) sets x = !x // bitwise not 30 | // if (zy == 1) sets y = 0 // 16-bit constant 31 | // if (ny == 1) sets y = !y // bitwise not 32 | // if (f == 1) sets out = x + y // integer 2's complement addition 33 | // if (f == 0) sets out = x & y // bitwise and 34 | // if (no == 1) sets out = !out // bitwise not 35 | void alu_chip(Alu *alu) 36 | { 37 | /* 38 | * INPUTS 39 | * X PRESETS 40 | */ 41 | // ZERO X 42 | Mux16 mux16_block_x = { 43 | .input.b = {[0 ... WORD_SIZE - 1] = 0}, 44 | .input.sel = alu->input.zx, 45 | }; 46 | memcpy(mux16_block_x.input.a, alu->input.x, sizeof(mux16_block_x.input.a)); 47 | mux16_chip(&mux16_block_x); 48 | 49 | // NOT X 50 | Not16 not16_block_x; 51 | memcpy(not16_block_x.input.in, mux16_block_x.output.out, sizeof(not16_block_x.input.in)); 52 | not16_gate(¬16_block_x); 53 | 54 | // X BLOCK OUT 55 | Mux16 mux16_block_x_out = { 56 | .input.sel = alu->input.nx}; 57 | memcpy(mux16_block_x_out.input.a, mux16_block_x.output.out, sizeof(mux16_block_x_out.input.a)); 58 | memcpy(mux16_block_x_out.input.b, not16_block_x.output.out, sizeof(mux16_block_x_out.input.b)); 59 | mux16_chip(&mux16_block_x_out); 60 | 61 | /* 62 | * Y PRESETS 63 | */ 64 | // ZERO Y 65 | Mux16 mux16_block_y = { 66 | .input.b = {[0 ... WORD_SIZE - 1] = 0}, 67 | .input.sel = alu->input.zy, 68 | }; 69 | memcpy(mux16_block_y.input.a, alu->input.y, sizeof(mux16_block_y.input.a)); 70 | mux16_chip(&mux16_block_y); 71 | 72 | // NOT Y 73 | Not16 not16_block_y; 74 | memcpy(not16_block_y.input.in, mux16_block_y.output.out, sizeof(not16_block_y.input.in)); 75 | not16_gate(¬16_block_y); 76 | 77 | // Y BLOCK OUT 78 | Mux16 mux16_block_y_out = { 79 | .input.sel = alu->input.ny}; 80 | memcpy(mux16_block_y_out.input.a, mux16_block_y.output.out, sizeof(mux16_block_y_out.input.a)); 81 | memcpy(mux16_block_y_out.input.b, not16_block_y.output.out, sizeof(mux16_block_y_out.input.b)); 82 | mux16_chip(&mux16_block_y_out); 83 | 84 | /* 85 | * HANDLE F 86 | */ 87 | And16 and16_block_f; 88 | memcpy(and16_block_f.input.a, mux16_block_x_out.output.out, sizeof(and16_block_f.input.a)); 89 | memcpy(and16_block_f.input.b, mux16_block_y_out.output.out, sizeof(and16_block_f.input.b)); 90 | and16_gate(&and16_block_f); 91 | 92 | Add16 add16_block_f; 93 | memcpy(add16_block_f.input.a, mux16_block_x_out.output.out, sizeof(add16_block_f.input.a)); 94 | memcpy(add16_block_f.input.b, mux16_block_y_out.output.out, sizeof(add16_block_f.input.b)); 95 | add16_chip(&add16_block_f); 96 | 97 | // CHOOSE function 98 | Mux16 mux16_block_f_out = { 99 | .input.sel = alu->input.f, 100 | }; 101 | memcpy(mux16_block_f_out.input.a, and16_block_f.output.out, sizeof(mux16_block_f_out.input.a)); 102 | memcpy(mux16_block_f_out.input.b, add16_block_f.output.out, sizeof(mux16_block_f_out.input.b)); 103 | mux16_chip(&mux16_block_f_out); 104 | 105 | /* 106 | * OUTPUTS 107 | * NO 108 | */ 109 | Not16 not16_block_no; 110 | memcpy(not16_block_no.input.in, mux16_block_f_out.output.out, sizeof(not16_block_no.input.in)); 111 | not16_gate(¬16_block_no); 112 | 113 | Mux16 mux16_block_no_out = { 114 | .input.sel = alu->input.no, 115 | }; 116 | memcpy(mux16_block_no_out.input.a, mux16_block_f_out.output.out, sizeof(mux16_block_no_out.input.a)); 117 | memcpy(mux16_block_no_out.input.b, not16_block_no.output.out, sizeof(mux16_block_no_out.input.b)); 118 | mux16_chip(&mux16_block_no_out); 119 | 120 | // ALU OUT 121 | memcpy(alu->output.out, mux16_block_no_out.output.out, sizeof(alu->output.out)); 122 | alu->output.ng = alu->output.out[15]; 123 | 124 | /* 125 | * ZR 126 | */ 127 | Or_8way or_8way_block_1, or_8way_block_2; 128 | memcpy(or_8way_block_1.input.in, &alu->output.out[0], sizeof(or_8way_block_1.input.in)); 129 | memcpy(or_8way_block_2.input.in, &alu->output.out[8], sizeof(or_8way_block_2.input.in)); 130 | or_8way_gate(&or_8way_block_1); 131 | or_8way_gate(&or_8way_block_2); 132 | 133 | Or or_unit = { 134 | .input.a = or_8way_block_1.output.out, 135 | .input.b = or_8way_block_2.output.out, 136 | }; 137 | or_gate(&or_unit); 138 | 139 | Not not_unit = { 140 | .input.in = or_unit.output.out, 141 | }; 142 | not_gate(¬_unit); 143 | 144 | alu->output.zr = not_unit.output.out; 145 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | NandToTetris is a course which has you build a full computer from "scratch": 3 | 4 | Logic gates -> Chips -> RAM -> CPU -> Computer 5 | -> Assembler -> Compiler -> OS -> Tetris 6 | 7 | All this is done via software defined hardware emulation. 8 | 9 | *I'm building an emulator for this entire stack in C.* 10 | 11 | ## Difference to other Emulator projects 12 | - No external dependencies (so far) 13 | - Start with a single software defined NAND gate in C 14 | - The first chips are built from this NAND gate 15 | - Then these chips are used and combined to build even more chips 16 | - Technically you could build EVERYTHING from just NAND gates, but that would take too long to code up 17 | - When I complete this project, I may write a script that converts all my non NAND gate components to pure NAND gates 18 | - Don't use certain programming utilities: boolean logic operators, bitwise logic operators etc 19 | - Instead we leverage the gates/chips to implement such logic 20 | - Build more and more base chips from the NAND gate 21 | - Simple gates: OR, AND, NOT, XOR 22 | - Simple chips: DMux, Mux 23 | - 16 bit variants 24 | 25 | For comparison, most emulator projects start right at the CPU level and don't sequentially build primitive structures 26 | - They look at CPU truth table / Instruction set and implement that logic directly 27 | - More straight forward, but you skip all the gates/chips fun. 28 | 29 | ## Contributing [OPEN] 30 | A really simple way to start contributing would be to write some truth table tests for the logic gates, then move up to more complex components. 31 | 32 | *Please see `docs/testing.md` to get started.* 33 | 34 | Heres an example test for a nand gate 35 | 36 | ```c 37 | #include 38 | 39 | #include "test-nand.h" 40 | #include "nand.h" 41 | #include "test-utils.h" 42 | 43 | void test_nand(Test_Counter *counter) 44 | { 45 | // Truth table for NAND: expected outputs 46 | const int expected[4] = {1, 1, 1, 0}; // outputs for (0,0), (0,1), (1,0), (1,1) 47 | for (int i = 0; i < 4; i++) 48 | { 49 | Nand nand = { 50 | .input.a = (i >> 1) & 1, // Gets first bit (0011) 51 | .input.b = i & 1, // Gets second bit (0101) 52 | }; 53 | nand_gate(&nand); 54 | test_assert(nand.output.out == expected[i], counter, 55 | "NAND(%d,%d) should be %d", 56 | nand.input.a, 57 | nand.input.b, 58 | expected[i]); 59 | } 60 | } 61 | ``` 62 | 63 | ## Example code, what to expect 64 | 65 | Confused? Some code example may help. 66 | 67 | ### Simple Gates 68 | 69 | #### NAND Gate 70 | Heres example code for my NAND gate: 71 | 72 | ```c 73 | /* 74 | * | a | b | out | 75 | * --------------- 76 | * | 0 | 0 | 1 | 77 | * | 0 | 1 | 1 | 78 | * | 1 | 0 | 1 | 79 | * | 1 | 1 | 0 | 80 | */ 81 | 82 | typedef struct Nand_Input 83 | { 84 | bool a; 85 | bool b; 86 | } Nand_Input; 87 | 88 | typedef struct Nand_Output 89 | { 90 | bool out; 91 | } Nand_Output; 92 | 93 | typedef struct Nand 94 | { 95 | Nand_Input input; 96 | Nand_Output output; 97 | } Nand; 98 | 99 | void nand_gate(Nand *nand_unit) 100 | { 101 | nand_unit->output.out = !(nand_unit->input.a & nand_unit->input.b); 102 | } 103 | ``` 104 | 105 | #### NOT Gate 106 | From this gate I build a NOT gate (note, no boolean operators) 107 | 108 | ```c 109 | typedef struct Not_Input 110 | { 111 | bool in; 112 | } Not_Input; 113 | 114 | typedef struct Not_Output 115 | { 116 | bool out; 117 | } Not_Output; 118 | 119 | typedef struct Not 120 | { 121 | Not_Input input; 122 | Not_Output output; 123 | } Not; 124 | 125 | void not_gate(Not *not_unit) 126 | { 127 | Nand nand_unit = { 128 | .input.a = not_unit->input.in, 129 | .input.b = not_unit->input.in, 130 | }; 131 | nand_gate(&nand_unit); 132 | not_unit->output.out = nand_unit.output.out; 133 | } 134 | ``` 135 | 136 | Then OR / AND / XOR / MUX / DMUX ..... and their 16 bit versions. 137 | 138 | ### Combinatorial Chips 139 | #### 8-way DMUX 140 | Heres a more complex chip, a 8-way DMux 141 | 142 | ```c 143 | /* 144 | * [a, b, c, d, e, f, g, h] = [in, 0, 0, 0, 0, 0, 0, 0] if sel = 000 145 | * [0, in, 0, 0, 0, 0, 0, 0] if sel = 001 146 | * [0, 0, in, 0, 0, 0, 0, 0] if sel = 010 147 | * [0, 0, 0, in, 0, 0, 0, 0] if sel = 011 148 | * [0, 0, 0, 0, in, 0, 0, 0] if sel = 100 149 | * [0, 0, 0, 0, 0, in, 0, 0] if sel = 101 150 | * [0, 0, 0, 0, 0, 0, in, 0] if sel = 110 151 | * [0, 0, 0, 0, 0, 0, 0, in] if sel = 111 152 | */ 153 | 154 | typedef struct Dmux_8way_Input 155 | { 156 | bool in; 157 | bool sel[3]; 158 | } Dmux_8way_Input; 159 | 160 | typedef struct Dmux_8way_Output 161 | { 162 | bool a; 163 | bool b; 164 | bool c; 165 | bool d; 166 | bool e; 167 | bool f; 168 | bool g; 169 | bool h; 170 | } Dmux_8way_Output; 171 | 172 | typedef struct Dmux_8way 173 | { 174 | Dmux_8way_Input input; 175 | Dmux_8way_Output output; 176 | } Dmux_8way; 177 | 178 | void dmux_8way_chip(Dmux_8way *dmux_8way_unit) 179 | { 180 | Dmux dmux_unit; 181 | Dmux_4way dmux_4way_unit_1, dmux_4way_unit_2; 182 | 183 | // dmux 184 | dmux_unit.input.in = dmux_8way_unit->input.in; 185 | dmux_unit.input.sel = dmux_8way_unit->input.sel[2]; 186 | dmux_chip(&dmux_unit); 187 | 188 | dmux_4way_unit_1.input.in = dmux_unit.output.a; 189 | memcpy(dmux_4way_unit_1.input.sel, dmux_8way_unit->input.sel, sizeof(dmux_4way_unit_1.input.sel)); 190 | dmux_4way_chip(&dmux_4way_unit_1); 191 | 192 | dmux_4way_unit_2.input.in = dmux_unit.output.b; 193 | memcpy(dmux_4way_unit_2.input.sel, dmux_8way_unit->input.sel, sizeof(dmux_4way_unit_2.input.sel)); 194 | dmux_4way_chip(&dmux_4way_unit_2); 195 | 196 | dmux_8way_unit->output.a = dmux_4way_unit_1.output.a; 197 | dmux_8way_unit->output.b = dmux_4way_unit_1.output.b; 198 | dmux_8way_unit->output.c = dmux_4way_unit_1.output.c; 199 | dmux_8way_unit->output.d = dmux_4way_unit_1.output.d; 200 | dmux_8way_unit->output.e = dmux_4way_unit_2.output.a; 201 | dmux_8way_unit->output.f = dmux_4way_unit_2.output.b; 202 | dmux_8way_unit->output.g = dmux_4way_unit_2.output.c; 203 | dmux_8way_unit->output.h = dmux_4way_unit_2.output.d; 204 | } 205 | ``` 206 | 207 | #### 16-bit 8 way Mux 208 | ```c 209 | /* 210 | * out = a if sel = 000 211 | * b if sel = 001 212 | * c if sel = 010 213 | * d if sel = 011 214 | * e if sel = 100 215 | * f if sel = 101 216 | * g if sel = 110 217 | * h if sel = 111 218 | */ 219 | 220 | typedef struct Mux16_8way_Input 221 | { 222 | bool a[WORD_SIZE]; 223 | bool b[WORD_SIZE]; 224 | bool c[WORD_SIZE]; 225 | bool d[WORD_SIZE]; 226 | bool e[WORD_SIZE]; 227 | bool f[WORD_SIZE]; 228 | bool g[WORD_SIZE]; 229 | bool h[WORD_SIZE]; 230 | bool sel[3]; 231 | } Mux16_8way_Input; 232 | 233 | typedef struct Mux16_8way_Output 234 | { 235 | bool out[WORD_SIZE]; 236 | } Mux16_8way_Output; 237 | 238 | typedef struct Mux16_8way 239 | { 240 | Mux16_8way_Input input; 241 | Mux16_8way_Output output; 242 | } Mux16_8way; 243 | 244 | void mux16_8way_chip(Mux16_8way *mux16_8way_unit) 245 | { 246 | Mux16_4way mux16_4way_unit_1, mux16_4way_unit_2; 247 | Mux16 mux16_unit; 248 | 249 | memcpy(mux16_4way_unit_1.input.sel, mux16_8way_unit->input.sel, sizeof(mux16_4way_unit_1.input.sel)); 250 | memcpy(mux16_4way_unit_1.input.a, mux16_8way_unit->input.a, sizeof(mux16_4way_unit_1.input.a)); 251 | memcpy(mux16_4way_unit_1.input.b, mux16_8way_unit->input.b, sizeof(mux16_4way_unit_1.input.b)); 252 | memcpy(mux16_4way_unit_1.input.c, mux16_8way_unit->input.c, sizeof(mux16_4way_unit_1.input.c)); 253 | memcpy(mux16_4way_unit_1.input.d, mux16_8way_unit->input.d, sizeof(mux16_4way_unit_1.input.d)); 254 | mux16_4way_chip(&mux16_4way_unit_1); 255 | 256 | memcpy(mux16_4way_unit_2.input.sel, mux16_8way_unit->input.sel, sizeof(mux16_4way_unit_2.input.sel)); 257 | memcpy(mux16_4way_unit_2.input.a, mux16_8way_unit->input.e, sizeof(mux16_4way_unit_2.input.a)); 258 | memcpy(mux16_4way_unit_2.input.b, mux16_8way_unit->input.f, sizeof(mux16_4way_unit_2.input.b)); 259 | memcpy(mux16_4way_unit_2.input.c, mux16_8way_unit->input.g, sizeof(mux16_4way_unit_2.input.c)); 260 | memcpy(mux16_4way_unit_2.input.d, mux16_8way_unit->input.h, sizeof(mux16_4way_unit_2.input.d)); 261 | mux16_4way_chip(&mux16_4way_unit_2); 262 | 263 | mux16_unit.input.sel = mux16_8way_unit->input.sel[2]; 264 | memcpy(mux16_unit.input.a, mux16_4way_unit_1.output.out, sizeof(mux16_unit.input.a)); 265 | memcpy(mux16_unit.input.b, mux16_4way_unit_2.output.out, sizeof(mux16_unit.input.b)); 266 | mux16_chip(&mux16_unit); 267 | 268 | memcpy(mux16_8way_unit->output.out, mux16_unit.output.out, sizeof(mux16_8way_unit->output.out)); 269 | } 270 | ``` 271 | 272 | ## Progress 273 | I have only started this project yesterday, so have completed 1 out of 7 hardware projects so far. 274 | I plan to build out the full PC this way, then begin work writing an Assembler in C. 275 | --------------------------------------------------------------------------------