From b231ac8e8275beeca6c53765f479c1a3cfa4aeb8 Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Mon, 4 Mar 2019 12:43:55 -0800 Subject: [PATCH 01/10] initial commit plus add short descriptions of what files do --- ls8/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ls8/README.md b/ls8/README.md index bb8d4fb4..016c14d1 100644 --- a/ls8/README.md +++ b/ls8/README.md @@ -66,6 +66,27 @@ but you'll have to implement those three above instructions first! * Read this whole file. * Skim the spec. +## File Structure + +* Examples - holds multiple files that gives us CPU word, instructions, register and operand examples + +### Cpu.c + +1. cpu_load - will load the binary bytes that are in .lsa source into an array + +2. alu - will handle the numeric values + +3. cpu_run - will handle processing all the instructions we feed it + +4. cpu_init - creates a cpu struct and starts the PC and all its registers + +### Cpu.h + +1. struct cpu - holds all info about CPU the registers and ram + +2. enum alu_op - all the ALU numeric operations + + ## Step 1: Implement `struct cpu` in `cpu.h` This structure holds information about the CPU and associated components. From ff85396097e7b980503ed94b3bf2f3b57c1f3d47 Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Mon, 4 Mar 2019 12:46:37 -0800 Subject: [PATCH 02/10] implemented struct cpu in cpu.h --- ls8/cpu.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..9cea236d 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -2,17 +2,22 @@ #define _CPU_H_ // Holds all information about the CPU -struct cpu { +struct cpu +{ // TODO // PC + unsigned char pc; // registers (array) + unsigned char registers[8]; // ram (array) + unsigned char ram[256]; }; // ALU operations -enum alu_op { - ALU_MUL - // Add more here +enum alu_op +{ + ALU_MUL + // Add more here }; // Instructions @@ -20,9 +25,9 @@ enum alu_op { // These use binary literals. If these aren't available with your compiler, hex // literals should be used. -#define LDI 0b10000010 -#define HLT 0b00000001 -#define PRN 0b01000111 +#define LDI 0b10000010 +#define HLT 0b00000001 +#define PRN 0b01000111 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations From e654bb0fe9830973e98bf5338f8aab8b96dd331b Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Mon, 4 Mar 2019 13:10:53 -0800 Subject: [PATCH 03/10] implemented cpu_init --- ls8/cpu.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..0fc7ab12 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -8,18 +8,19 @@ void cpu_load(struct cpu *cpu) { char data[DATA_LEN] = { - // From print8.ls8 - 0b10000010, // LDI R0,8 - 0b00000000, - 0b00001000, - 0b01000111, // PRN R0 - 0b00000000, - 0b00000001 // HLT + // From print8.ls8 + 0b10000010, // LDI R0,8 + 0b00000000, + 0b00001000, + 0b01000111, // PRN R0 + 0b00000000, + 0b00000001 // HLT }; int address = 0; - for (int i = 0; i < DATA_LEN; i++) { + for (int i = 0; i < DATA_LEN; i++) + { cpu->ram[address++] = data[i]; } @@ -31,10 +32,11 @@ void cpu_load(struct cpu *cpu) */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { - switch (op) { - case ALU_MUL: - // TODO - break; + switch (op) + { + case ALU_MUL: + // TODO + break; // TODO: implement more ALU ops } @@ -47,7 +49,8 @@ void cpu_run(struct cpu *cpu) { int running = 1; // True until we get a HLT instruction - while (running) { + while (running) + { // TODO // 1. Get the value of the current instruction (in address PC). // 2. Figure out how many operands this next instruction requires @@ -64,4 +67,8 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { // TODO: Initialize the PC and other special registers + cpu->pc = 0; + memset(cpu->ram, 0, 8 * sizeof(char)); + memset(cpu->registers, 0, 256 * sizeof(char)); + return 0; } From c22bda430f71cf3c1211812394f0651624c1b8e7 Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Mon, 4 Mar 2019 15:46:39 -0800 Subject: [PATCH 04/10] refactored cpu_init && implemented cpu_rn --- ls8/cpu.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 0fc7ab12..04f88aba 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -53,12 +53,33 @@ void cpu_run(struct cpu *cpu) { // TODO // 1. Get the value of the current instruction (in address PC). + unsigned char ir = cpu_ram_read(cpu, cpu->pc); // 2. Figure out how many operands this next instruction requires // 3. Get the appropriate value(s) of the operands following this instruction + unsigned char operandA = cpu_ram_read(cpu, cpu->pc + 1); + unsigned char operandB = cpu_ram_read(cpu, cpu->pc + 2); // 4. switch() over it to decide on a course of action. - // 5. Do whatever the instruction should do according to the spec. - // 6. Move the PC to the next instruction. + switch (ir) + { + case HLT: + running = 0; + break; + case LDI: + cpu->registers[operandA] = operandB; + cpu->pc += 3; + break; + case PRN: + printf("%d\n", cpu->registers[operandA]); + cpu->pc += 2; + break; + default: + printf("Unknown Command. Exiting...\n"); + exit(3); + } } + + // 5. Do whatever the instruction should do according to the spec. + // 6. Move the PC to the next instruction. } /** @@ -67,8 +88,18 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { // TODO: Initialize the PC and other special registers + // Init Registers + for (int i = 0; i < 7; i++) + { + cpu->registers[i] = 0; + } + + cpu->registers[7] = 0xF4; + // Init PC cpu->pc = 0; - memset(cpu->ram, 0, 8 * sizeof(char)); + // Init Ram + memset(cpu->ram, 0, sizeof(cpu->ram)); + memset(cpu->registers, 0, 256 * sizeof(char)); return 0; } From b8baf8407a284af72df5225f9ee8558be0dc736d Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Tue, 5 Mar 2019 16:20:12 -0800 Subject: [PATCH 05/10] implemented ls8 fun & duggin --- ls8/cpu.c | 23 ++++++++++++++++++----- ls8/cpu.h | 2 +- ls8/ls8.c | 14 +++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 04f88aba..e413fc97 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,3 +1,6 @@ +#include +#include +#include #include "cpu.h" #define DATA_LEN 6 @@ -32,6 +35,9 @@ void cpu_load(struct cpu *cpu) */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { + (void)cpu; + (void)regA; + (void)regB; switch (op) { case ALU_MUL: @@ -41,7 +47,14 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB // TODO: implement more ALU ops } } - +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char MAR) +{ + return cpu->ram[MAR]; +} +unsigned char cpu_ram_write(struct cpu *cpu, unsigned char MAR, unsigned char MDR) +{ + return cpu->ram[MAR] = MDR; +} /** * Run the CPU */ @@ -73,8 +86,8 @@ void cpu_run(struct cpu *cpu) cpu->pc += 2; break; default: - printf("Unknown Command. Exiting...\n"); - exit(3); + printf("Unknown instruction 0x%02X at 0x%02X\n", ir, cpu->pc); + exit(1); } } @@ -100,6 +113,6 @@ void cpu_init(struct cpu *cpu) // Init Ram memset(cpu->ram, 0, sizeof(cpu->ram)); - memset(cpu->registers, 0, 256 * sizeof(char)); - return 0; + // memset(cpu->registers, 0, 256 * sizeof(char)); + // return 0; } diff --git a/ls8/cpu.h b/ls8/cpu.h index 9cea236d..bb4f891f 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -32,7 +32,7 @@ enum alu_op // Function declarations -extern void cpu_load(struct cpu *cpu); +extern void cpu_load(struct cpu *cpu, char *filename); extern void cpu_init(struct cpu *cpu); extern void cpu_run(struct cpu *cpu); diff --git a/ls8/ls8.c b/ls8/ls8.c index d24578ee..93335387 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,13 +4,21 @@ /** * Main */ -int main(void) +int main(int argc, char *argv) { struct cpu cpu; + if (argc != 2) + { + printf(stderr, "useage: ls8 \n"); + return 1; + } + + char *filename = argv[1]; + cpu_init(&cpu); - cpu_load(&cpu); + cpu_load(&cpu, filename); cpu_run(&cpu); return 0; -} \ No newline at end of file +}; From e4108f870836e217c785b7d8b25d1d62503901fb Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Tue, 5 Mar 2019 17:16:55 -0800 Subject: [PATCH 06/10] defined MUL & ADD --- .vscode/settings.json | 11 +++++++++++ ls8/cpu.h | 2 ++ 2 files changed, 13 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..fcddcac7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "workbench.colorCustomizations": { + "activityBar.background": "#033615", + "titleBar.activeBackground": "#044B1D", + "titleBar.activeForeground": "#F0FEF5" + }, + "files.associations": { + "*.js": "javascriptreact", + "cpu.h": "c" + } +} \ No newline at end of file diff --git a/ls8/cpu.h b/ls8/cpu.h index bb4f891f..9075a6b7 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -28,6 +28,8 @@ enum alu_op #define LDI 0b10000010 #define HLT 0b00000001 #define PRN 0b01000111 +#define MUL 0b10100010 +#define ADD 0b10100000 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations From 2f03dcbec007cf735e244cdc31bb5897ee9bf258 Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Tue, 5 Mar 2019 17:22:56 -0800 Subject: [PATCH 07/10] added ALU op & implemented switch --- .vscode/settings.json | 3 ++- ls8/cpu.c | 8 ++++++++ ls8/cpu.h | 4 +++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index fcddcac7..98cb24c4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ }, "files.associations": { "*.js": "javascriptreact", - "cpu.h": "c" + "cpu.h": "c", + "stdlib.h": "c" } } \ No newline at end of file diff --git a/ls8/cpu.c b/ls8/cpu.c index e413fc97..130689b1 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -85,6 +85,14 @@ void cpu_run(struct cpu *cpu) printf("%d\n", cpu->registers[operandA]); cpu->pc += 2; break; + case MUL: + alu(cpu, ALU_MUL, operandA, operandB); + cpu->pc += 3; + break; + case ADD: + alu(cpu, ALU_ADD, operandA, operandB); + cpu->pc += 3; + break; default: printf("Unknown instruction 0x%02X at 0x%02X\n", ir, cpu->pc); exit(1); diff --git a/ls8/cpu.h b/ls8/cpu.h index 9075a6b7..6848c3a0 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -16,7 +16,9 @@ struct cpu // ALU operations enum alu_op { - ALU_MUL + ALU_MUL, + ALU_ADD + // Add more here }; From 41d465ed69aa85c216ef0328b2458838923e1365 Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Tue, 5 Mar 2019 17:25:45 -0800 Subject: [PATCH 08/10] implemented cpu_load --- ls8/cpu.c | 40 +++++++++++++++++++++++++--------------- ls8/ls8.c | 2 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 130689b1..bd8c999b 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -10,23 +10,31 @@ */ void cpu_load(struct cpu *cpu) { - char data[DATA_LEN] = { - // From print8.ls8 - 0b10000010, // LDI R0,8 - 0b00000000, - 0b00001000, - 0b01000111, // PRN R0 - 0b00000000, - 0b00000001 // HLT - }; + FILE *fp = fopen(path, "r"); + char line[8000]; + + if (fp == NULL) + { + printf("Couldn't open program: %s\n", path); + exit(2); + } int address = 0; - for (int i = 0; i < DATA_LEN; i++) + while (fgets(line, sizeof(line), fp) != NULL) { - cpu->ram[address++] = data[i]; + char *endptr; + + unsigned char value = strtoul(line, &endptr, 2) & 0xFF; + if (endptr == line) + { + continue; + } + cpu_ram_write(cpu, address++, value); } + fclose(fp); + // TODO: Replace this with something less hard-coded } @@ -35,13 +43,15 @@ void cpu_load(struct cpu *cpu) */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { - (void)cpu; - (void)regA; - (void)regB; + unsigned int a = cpu->registers[regA]; + unsigned int b = cpu->registers[regB]; switch (op) { case ALU_MUL: - // TODO + cpu->registers[regA] = a * b; + break; + case ALU_ADD: + cpu->registers[regA] = a + b; break; // TODO: implement more ALU ops diff --git a/ls8/ls8.c b/ls8/ls8.c index 93335387..73c78fbe 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -14,7 +14,7 @@ int main(int argc, char *argv) return 1; } - char *filename = argv[1]; + char filename = argv[1]; cpu_init(&cpu); cpu_load(&cpu, filename); From 43541fbb085a919a36af47b01188e8e21d0d63f0 Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Tue, 5 Mar 2019 17:26:21 -0800 Subject: [PATCH 09/10] path added to argument --- ls8/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index bd8c999b..197f4bf2 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -8,7 +8,7 @@ /** * Load the binary bytes from a .ls8 source file into a RAM array */ -void cpu_load(struct cpu *cpu) +void cpu_load(struct cpu *cpu, char *path) { FILE *fp = fopen(path, "r"); char line[8000]; From 776203a020254903013d5ce0d5570f4a244b62ef Mon Sep 17 00:00:00 2001 From: luiscmartinez Date: Wed, 6 Mar 2019 12:15:01 -0800 Subject: [PATCH 10/10] refactored files and variables --- ls8/cpu.c | 76 +++++++++++++++++++++++++------------------------------ ls8/cpu.h | 8 ++---- ls8/ls8.c | 12 ++++----- 3 files changed, 42 insertions(+), 54 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 197f4bf2..5d3ed380 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -5,26 +5,39 @@ #define DATA_LEN 6 +/** + * Reads from a CPU struct's RAM array + */ +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) +{ + return cpu->ram[address]; +} + +void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) +{ + cpu->ram[address] = value; +} + /** * Load the binary bytes from a .ls8 source file into a RAM array */ void cpu_load(struct cpu *cpu, char *path) { - FILE *fp = fopen(path, "r"); - char line[8000]; + FILE *fileptr = fopen(path, "r"); - if (fp == NULL) + if (fileptr == NULL) { printf("Couldn't open program: %s\n", path); exit(2); } int address = 0; + char line[8000]; - while (fgets(line, sizeof(line), fp) != NULL) + while (fgets(line, sizeof(line), fileptr) != NULL) { char *endptr; - + // & 0xFF gives you the last 8 bits of the ul (so it will always fit in an unsigned char) unsigned char value = strtoul(line, &endptr, 2) & 0xFF; if (endptr == line) { @@ -33,9 +46,7 @@ void cpu_load(struct cpu *cpu, char *path) cpu_ram_write(cpu, address++, value); } - fclose(fp); - - // TODO: Replace this with something less hard-coded + fclose(fileptr); } /** @@ -45,6 +56,7 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB { unsigned int a = cpu->registers[regA]; unsigned int b = cpu->registers[regB]; + switch (op) { case ALU_MUL: @@ -53,18 +65,9 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB case ALU_ADD: cpu->registers[regA] = a + b; break; - - // TODO: implement more ALU ops } } -unsigned char cpu_ram_read(struct cpu *cpu, unsigned char MAR) -{ - return cpu->ram[MAR]; -} -unsigned char cpu_ram_write(struct cpu *cpu, unsigned char MAR, unsigned char MDR) -{ - return cpu->ram[MAR] = MDR; -} + /** * Run the CPU */ @@ -74,24 +77,26 @@ void cpu_run(struct cpu *cpu) while (running) { - // TODO // 1. Get the value of the current instruction (in address PC). unsigned char ir = cpu_ram_read(cpu, cpu->pc); // 2. Figure out how many operands this next instruction requires + // Not entirely needed if we use a switch statement // 3. Get the appropriate value(s) of the operands following this instruction + // Operations may need up to 2 bytes after PC unsigned char operandA = cpu_ram_read(cpu, cpu->pc + 1); unsigned char operandB = cpu_ram_read(cpu, cpu->pc + 2); // 4. switch() over it to decide on a course of action. + // 5. Do whatever the instruction should do according to the spec. + // 6. Move the PC to the next instruction. switch (ir) { - case HLT: - running = 0; - break; case LDI: + // Set the value of a register to an integer cpu->registers[operandA] = operandB; cpu->pc += 3; break; case PRN: + // Print numeric value stored in the given register printf("%d\n", cpu->registers[operandA]); cpu->pc += 2; break; @@ -103,14 +108,14 @@ void cpu_run(struct cpu *cpu) alu(cpu, ALU_ADD, operandA, operandB); cpu->pc += 3; break; + case HLT: + // Halt the CPU (and exit the emulator) + running = 0; + break; default: - printf("Unknown instruction 0x%02X at 0x%02X\n", ir, cpu->pc); - exit(1); + break; } } - - // 5. Do whatever the instruction should do according to the spec. - // 6. Move the PC to the next instruction. } /** @@ -118,19 +123,8 @@ void cpu_run(struct cpu *cpu) */ void cpu_init(struct cpu *cpu) { - // TODO: Initialize the PC and other special registers - // Init Registers - for (int i = 0; i < 7; i++) - { - cpu->registers[i] = 0; - } - - cpu->registers[7] = 0xF4; - // Init PC cpu->pc = 0; - // Init Ram memset(cpu->ram, 0, sizeof(cpu->ram)); - - // memset(cpu->registers, 0, 256 * sizeof(char)); - // return 0; -} + memset(cpu->registers, 0, sizeof(cpu->registers)); + cpu->registers[7] = 0xF4; +} \ No newline at end of file diff --git a/ls8/cpu.h b/ls8/cpu.h index 6848c3a0..82ee1237 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -4,7 +4,6 @@ // Holds all information about the CPU struct cpu { - // TODO // PC unsigned char pc; // registers (array) @@ -18,8 +17,6 @@ enum alu_op { ALU_MUL, ALU_ADD - - // Add more here }; // Instructions @@ -32,12 +29,11 @@ enum alu_op #define PRN 0b01000111 #define MUL 0b10100010 #define ADD 0b10100000 -// TODO: more instructions here. These can be used in cpu_run(). // Function declarations -extern void cpu_load(struct cpu *cpu, char *filename); +extern void cpu_load(struct cpu *cpu, char *path); extern void cpu_init(struct cpu *cpu); extern void cpu_run(struct cpu *cpu); -#endif +#endif \ No newline at end of file diff --git a/ls8/ls8.c b/ls8/ls8.c index 73c78fbe..3a1778d2 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,21 +4,19 @@ /** * Main */ -int main(int argc, char *argv) +int main(int argc, char **argv) { - struct cpu cpu; - if (argc != 2) { - printf(stderr, "useage: ls8 \n"); + fprintf(stderr, "usage: must include a single path to a desired program\n"); return 1; } - char filename = argv[1]; + struct cpu cpu; cpu_init(&cpu); - cpu_load(&cpu, filename); + cpu_load(&cpu, argv[1]); cpu_run(&cpu); return 0; -}; +} \ No newline at end of file