From 8ce1aad78bd7782aeb6ea712c6de5558832d54e3 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 4 Mar 2019 15:11:11 -0500 Subject: [PATCH 01/19] initial commit --- ls8/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..62437ad9 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,7 +1,7 @@ #include "cpu.h" #define DATA_LEN 6 - + /** * Load the binary bytes from a .ls8 source file into a RAM array */ From 33e48c9171d6e2980bc08257cfa17e1dcaa0debc Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 4 Mar 2019 16:06:35 -0500 Subject: [PATCH 02/19] creates cpu_init function --- ls8/cpu.c | 4 +++- ls8/cpu.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 62437ad9..f34a1f81 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -63,5 +63,7 @@ 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(unsigned char)); + memset(cpu->registers, 0, 256 * sizeof(unsigned char)); } diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..4e0340b4 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -5,8 +5,11 @@ struct cpu { // TODO // PC + unsigned char PC; // registers (array) + unsigned char registers[8]; // ram (array) + unsigned char ram[256]; }; // ALU operations From 3eb21252f09ec137fd03419d9050f7af35f388fd Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 4 Mar 2019 16:11:32 -0500 Subject: [PATCH 03/19] adds ram functions --- ls8/cpu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index f34a1f81..4529001b 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,6 +1,16 @@ #include "cpu.h" #define DATA_LEN 6 + +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 From a007a0f5ca4d6756f112c7c017441f0ebe439528 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 4 Mar 2019 17:37:28 -0500 Subject: [PATCH 04/19] implements cpu_run core --- ls8/cpu.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index 4529001b..f0d140f7 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -60,9 +60,34 @@ 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 // 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. + switch(ir) + { + case LDI + { + cpu->PC += 2; + break; + } + case PRN + { + cpu->PC += 1; + break; + } + case HLT + { + running = 0; + break; + } + default + { + break; + } + } // 5. Do whatever the instruction should do according to the spec. // 6. Move the PC to the next instruction. } From 88ad0139e5be1c955f94bb28db15a16bb3f87f33 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 4 Mar 2019 17:55:12 -0500 Subject: [PATCH 05/19] completes day 1 MVP --- ls8/cpu.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index f0d140f7..eaf2417c 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,5 +1,6 @@ #include "cpu.h" - +#include +#include #define DATA_LEN 6 unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) @@ -66,24 +67,26 @@ void cpu_run(struct cpu *cpu) 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. - switch(ir) + switch (ir) { - case LDI + case LDI: { - cpu->PC += 2; + cpu->registers[operandA] = operandB; + cpu->PC += 3; break; } - case PRN + case PRN: { - cpu->PC += 1; + printf("%d\n", cpu->registers[operandA]); + cpu->PC += 2; break; } - case HLT + case HLT: { running = 0; break; } - default + default: { break; } @@ -98,7 +101,7 @@ void cpu_run(struct cpu *cpu) */ void cpu_init(struct cpu *cpu) { - cpu->pc = 0; + cpu->PC = 0; memset(cpu->ram, 0, 8 * sizeof(unsigned char)); memset(cpu->registers, 0, 256 * sizeof(unsigned char)); } From f4f9e9f4a1beff19006171b860538e260196e04e Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 5 Mar 2019 15:11:05 -0500 Subject: [PATCH 06/19] updates cpu_load to take in a file and ls8.c to pass command line args --- ls8/cpu.c | 2 +- ls8/cpu.h | 2 +- ls8/ls8.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index eaf2417c..94c19238 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -16,7 +16,7 @@ void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) /** * 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 *file) { char data[DATA_LEN] = { // From print8.ls8 diff --git a/ls8/cpu.h b/ls8/cpu.h index 4e0340b4..7410de0e 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -30,7 +30,7 @@ enum alu_op { // Function declarations -extern void cpu_load(struct cpu *cpu); +extern void cpu_load(struct cpu *cpu, char *file); 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..21754bf3 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,12 +4,12 @@ /** * Main */ -int main(void) +int main(int argc, char *argv[]) { struct cpu cpu; cpu_init(&cpu); - cpu_load(&cpu); + cpu_load(&cpu, argv[1]); cpu_run(&cpu); return 0; From 62bfb46280a7e7445c4993173ee7d88c0445f3c4 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 5 Mar 2019 15:42:39 -0500 Subject: [PATCH 07/19] updates cpu_load to no longer be hard coded --- ls8/cpu.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 94c19238..aee7db69 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -18,23 +18,22 @@ void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) */ void cpu_load(struct cpu *cpu, char *file) { - char data[DATA_LEN] = { - // From print8.ls8 - 0b10000010, // LDI R0,8 - 0b00000000, - 0b00001000, - 0b01000111, // PRN R0 - 0b00000000, - 0b00000001 // HLT - }; - + FILE *fp; + char line[1024]; int address = 0; - for (int i = 0; i < DATA_LEN; i++) { - cpu->ram[address++] = data[i]; - } + fp = fopen(file, "r"); + while(fgets(line, sizeof(line), fp) != NULL){ + char *endptr; + unsigned char value; + value = strtoul(line, &endptr, 2); - // TODO: Replace this with something less hard-coded + if(value == HLT) { + cpu->ram[address++] = value; + break; + } + cpu->ram[address++] = value; + } } /** @@ -57,7 +56,6 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB void cpu_run(struct cpu *cpu) { int running = 1; // True until we get a HLT instruction - while (running) { // TODO // 1. Get the value of the current instruction (in address PC). From f4eec600c8d5a3c1f2ee2c6d2bc50a81015acd98 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 5 Mar 2019 15:50:46 -0500 Subject: [PATCH 08/19] adds error handling for nonexistent files & not enough command line args --- ls8/cpu.c | 9 +++++++++ ls8/ls8.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index aee7db69..b7b674bb 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,6 +1,7 @@ #include "cpu.h" #include #include +#include #define DATA_LEN 6 unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) @@ -18,8 +19,16 @@ void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) */ void cpu_load(struct cpu *cpu, char *file) { + FILE *fp; char line[1024]; + + if ((fp = fopen(file, "r")) == NULL) + { + fprintf(stderr, "File not found.\n"); + exit(1); + } + int address = 0; fp = fopen(file, "r"); diff --git a/ls8/ls8.c b/ls8/ls8.c index 21754bf3..cea3c4a4 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -6,6 +6,11 @@ */ int main(int argc, char *argv[]) { + if (argc < 2) + { + fprintf(stderr, "A file must be given.\n"); + exit(1); + } struct cpu cpu; cpu_init(&cpu); From 53c3d94c048489eda18ae14c0f9c51c40a57b4d3 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 5 Mar 2019 16:30:54 -0500 Subject: [PATCH 09/19] multiply works, will implement in ALU later --- ls8/cpu.c | 15 ++++++++++++--- ls8/cpu.h | 1 + ls8/ls8.c | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index b7b674bb..4150ec4e 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -37,10 +37,12 @@ void cpu_load(struct cpu *cpu, char *file) unsigned char value; value = strtoul(line, &endptr, 2); - if(value == HLT) { - cpu->ram[address++] = value; - break; + if(endptr == line){ + // printf("Ignoring this line.\n"); + continue; } + + // printf("'line' - %s\n'value' - %d\n'address' - %d", line, value, address); cpu->ram[address++] = value; } } @@ -65,6 +67,7 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB void cpu_run(struct cpu *cpu) { int running = 1; // True until we get a HLT instruction + // printf("in run"); while (running) { // TODO // 1. Get the value of the current instruction (in address PC). @@ -82,6 +85,12 @@ void cpu_run(struct cpu *cpu) cpu->PC += 3; break; } + case MUL: + { + cpu->registers[operandA] *= cpu->registers[operandB]; + cpu->PC += 3; + break; + } case PRN: { printf("%d\n", cpu->registers[operandA]); diff --git a/ls8/cpu.h b/ls8/cpu.h index 7410de0e..f434aa44 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -26,6 +26,7 @@ enum alu_op { #define LDI 0b10000010 #define HLT 0b00000001 #define PRN 0b01000111 +#define MUL 0b10100010 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations diff --git a/ls8/ls8.c b/ls8/ls8.c index cea3c4a4..ab964617 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -1,4 +1,5 @@ #include +#include #include "cpu.h" /** From e1dabb51775d123a845eb78faa6ef59393663f68 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 5 Mar 2019 17:34:26 -0500 Subject: [PATCH 10/19] completes day 2 MVP --- ls8/cpu.c | 18 ++++++++++++++++-- ls8/cpu.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 4150ec4e..486512e3 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -79,6 +79,11 @@ void cpu_run(struct cpu *cpu) // 4. switch() over it to decide on a course of action. switch (ir) { + case HLT: + { + running = 0; + break; + } case LDI: { cpu->registers[operandA] = operandB; @@ -91,15 +96,23 @@ void cpu_run(struct cpu *cpu) cpu->PC += 3; break; } + case POP: + { + cpu->registers[operandA] = cpu_ram_read(cpu, cpu->registers[7]); + cpu->ram[cpu->registers[7]++] = 0x00; + cpu->PC += 2; + break; + } case PRN: { printf("%d\n", cpu->registers[operandA]); cpu->PC += 2; break; } - case HLT: + case PUSH: { - running = 0; + cpu_ram_write(cpu, --cpu->registers[7], cpu->registers[operandA]); + cpu->PC += 2; break; } default: @@ -120,4 +133,5 @@ void cpu_init(struct cpu *cpu) cpu->PC = 0; memset(cpu->ram, 0, 8 * sizeof(unsigned char)); memset(cpu->registers, 0, 256 * sizeof(unsigned char)); + cpu->registers[7] = 0xF4; } diff --git a/ls8/cpu.h b/ls8/cpu.h index f434aa44..64f3494c 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -27,6 +27,8 @@ enum alu_op { #define HLT 0b00000001 #define PRN 0b01000111 #define MUL 0b10100010 +#define POP 0b01000110 +#define PUSH 0b01000101 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations From 75e1da06e8bebf47bbf838a56f22f7c3fb078253 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Wed, 6 Mar 2019 15:14:26 -0500 Subject: [PATCH 11/19] adds flag to cpu struct --- ls8/cpu.c | 1 + ls8/cpu.h | 1 + 2 files changed, 2 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index 486512e3..14eaed71 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -131,6 +131,7 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { cpu->PC = 0; + cpu->FL = 0; memset(cpu->ram, 0, 8 * sizeof(unsigned char)); memset(cpu->registers, 0, 256 * sizeof(unsigned char)); cpu->registers[7] = 0xF4; diff --git a/ls8/cpu.h b/ls8/cpu.h index 64f3494c..bb737334 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -6,6 +6,7 @@ struct cpu { // TODO // PC unsigned char PC; + unsigned char FL; // registers (array) unsigned char registers[8]; // ram (array) From 884968395613e8cbcfce847650931c292859a547 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Thu, 7 Mar 2019 13:54:53 -0500 Subject: [PATCH 12/19] adds add instruction --- ls8/cpu.c | 5 +++++ ls8/cpu.h | 1 + 2 files changed, 6 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index 14eaed71..79265f48 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -79,6 +79,11 @@ void cpu_run(struct cpu *cpu) // 4. switch() over it to decide on a course of action. switch (ir) { + case ADD: + { + cpu->registers[operandA] += cpu->registers[operandB]; + break; + } case HLT: { running = 0; diff --git a/ls8/cpu.h b/ls8/cpu.h index bb737334..76815193 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -30,6 +30,7 @@ enum alu_op { #define MUL 0b10100010 #define POP 0b01000110 #define PUSH 0b01000101 +#define ADD 0b10100000 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations From 50a3abc55e5f29a091c2a96baf4edfc92117c993 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Thu, 7 Mar 2019 16:08:22 -0500 Subject: [PATCH 13/19] completes call and return --- ls8/cpu.c | 30 +++++++++++++++++++++++------- ls8/cpu.h | 2 ++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 79265f48..2b727a85 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -74,8 +74,21 @@ void cpu_run(struct cpu *cpu) 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); + unsigned char operandA; + unsigned char operandB; + int next_line = 1; + + if (ir & 0x80) + { + operandA = cpu->ram[(cpu->PC + 1) & 0xff]; + operandB = cpu->ram[(cpu->PC + 2) & 0xff]; + next_line = 3; + } + else if (ir & 0x40) + { + operandA = cpu->ram[(cpu->PC + 1) & 0xff]; + next_line = 2; + } // 4. switch() over it to decide on a course of action. switch (ir) { @@ -84,6 +97,13 @@ void cpu_run(struct cpu *cpu) cpu->registers[operandA] += cpu->registers[operandB]; break; } + case CALL: + cpu->ram[--cpu->registers[7]] = cpu->PC + next_line; + cpu->PC = cpu->registers[operandA]; + continue; + case RET: + cpu->PC = cpu->ram[cpu->registers[7]++]; + continue; case HLT: { running = 0; @@ -92,32 +112,27 @@ void cpu_run(struct cpu *cpu) case LDI: { cpu->registers[operandA] = operandB; - cpu->PC += 3; break; } case MUL: { cpu->registers[operandA] *= cpu->registers[operandB]; - cpu->PC += 3; break; } case POP: { cpu->registers[operandA] = cpu_ram_read(cpu, cpu->registers[7]); cpu->ram[cpu->registers[7]++] = 0x00; - cpu->PC += 2; break; } case PRN: { printf("%d\n", cpu->registers[operandA]); - cpu->PC += 2; break; } case PUSH: { cpu_ram_write(cpu, --cpu->registers[7], cpu->registers[operandA]); - cpu->PC += 2; break; } default: @@ -125,6 +140,7 @@ void cpu_run(struct cpu *cpu) break; } } + cpu->PC = cpu->PC + next_line; // 5. Do whatever the instruction should do according to the spec. // 6. Move the PC to the next instruction. } diff --git a/ls8/cpu.h b/ls8/cpu.h index 76815193..897142dd 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -31,6 +31,8 @@ enum alu_op { #define POP 0b01000110 #define PUSH 0b01000101 #define ADD 0b10100000 +#define CALL 0b01010000 +#define RET 0b00010001 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations From 532b27871bca2e7ea59393e6359fe7b52a05e2d8 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Fri, 8 Mar 2019 11:09:46 -0500 Subject: [PATCH 14/19] adds CMP, JEQ, JMP, and JNE definitions --- ls8/cpu.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ls8/cpu.h b/ls8/cpu.h index 897142dd..46133e19 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -32,7 +32,11 @@ enum alu_op { #define PUSH 0b01000101 #define ADD 0b10100000 #define CALL 0b01010000 -#define RET 0b00010001 +#define RET 0b00010001 +#define CMP 0b10100111 +#define JEQ 0b01010101 +#define JMP 0b01010100 +#define JNE 0b01010110 // TODO: more instructions here. These can be used in cpu_run(). // Function declarations From 76f39978ef8681a883747310053a673fa47599ff Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Fri, 8 Mar 2019 11:33:04 -0500 Subject: [PATCH 15/19] adds E, L, and G flags to CPU and adds CMP case --- ls8/cpu.c | 21 +++++++++++++++++++++ ls8/cpu.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index 2b727a85..033f993f 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -104,6 +104,24 @@ void cpu_run(struct cpu *cpu) case RET: cpu->PC = cpu->ram[cpu->registers[7]++]; continue; + case CMP: + { + if (cpu->registers[operandA] == cpu->registers[operandB]) + { + cpu->E = 1; + break; + } + else if (cpu->registers[operandA] > cpu->registers[operandB]) + { + cpu->G = 1; + break; + } + else + { + cpu->L = 1; + break; + } + } case HLT: { running = 0; @@ -153,6 +171,9 @@ void cpu_init(struct cpu *cpu) { cpu->PC = 0; cpu->FL = 0; + cpu->E = 0; + cpu->L = 0; + cpu->G = 0; memset(cpu->ram, 0, 8 * sizeof(unsigned char)); memset(cpu->registers, 0, 256 * sizeof(unsigned char)); cpu->registers[7] = 0xF4; diff --git a/ls8/cpu.h b/ls8/cpu.h index 46133e19..365b492f 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -7,6 +7,9 @@ struct cpu { // PC unsigned char PC; unsigned char FL; + unsigned char E; + unsigned char L; + unsigned char G; // registers (array) unsigned char registers[8]; // ram (array) From 8381512df250716aa737f4898ede37998d9bb295 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Fri, 8 Mar 2019 11:40:58 -0500 Subject: [PATCH 16/19] completes MVP --- ls8/cpu.c | 23 +++++++++++ ls8/examples/sctest.ls8 | 86 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 ls8/examples/sctest.ls8 diff --git a/ls8/cpu.c b/ls8/cpu.c index 033f993f..132fb43a 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -127,6 +127,29 @@ void cpu_run(struct cpu *cpu) running = 0; break; } + case JEQ: + { + if (cpu->E == 1) + { + cpu->PC = cpu->registers[operandA]; + continue; + } + break; + } + case JMP: + { + cpu->PC = cpu->registers[operandA]; + continue; + } + case JNE: + { + if (cpu->E != 1) + { + cpu->PC = cpu->registers[operandA]; + continue; + } + break; + } case LDI: { cpu->registers[operandA] = operandB; diff --git a/ls8/examples/sctest.ls8 b/ls8/examples/sctest.ls8 new file mode 100644 index 00000000..8f86bba7 --- /dev/null +++ b/ls8/examples/sctest.ls8 @@ -0,0 +1,86 @@ +# Code to test the Sprint Challenge +# +# Expected output: +# 1 +# 4 +# 5 + +10000010 # LDI R0,10 +00000000 +00001010 +10000010 # LDI R1,20 +00000001 +00010100 +10000010 # LDI R2,TEST1 +00000010 +00010011 +10100111 # CMP R0,R1 +00000000 +00000001 +01010101 # JEQ R2 +00000010 +10000010 # LDI R3,1 +00000011 +00000001 +01000111 # PRN R3 +00000011 +# TEST1 (address 19): +10000010 # LDI R2,TEST2 +00000010 +00100000 +10100111 # CMP R0,R1 +00000000 +00000001 +01010110 # JNE R2 +00000010 +10000010 # LDI R3,2 +00000011 +00000010 +01000111 # PRN R3 +00000011 +# TEST2 (address 32): +10000010 # LDI R1,10 +00000001 +00001010 +10000010 # LDI R2,TEST3 +00000010 +00110000 +10100111 # CMP R0,R1 +00000000 +00000001 +01010101 # JEQ R2 +00000010 +10000010 # LDI R3,3 +00000011 +00000011 +01000111 # PRN R3 +00000011 +# TEST3 (address 48): +10000010 # LDI R2,TEST4 +00000010 +00111101 +10100111 # CMP R0,R1 +00000000 +00000001 +01010110 # JNE R2 +00000010 +10000010 # LDI R3,4 +00000011 +00000100 +01000111 # PRN R3 +00000011 +# TEST4 (address 61): +10000010 # LDI R3,5 +00000011 +00000101 +01000111 # PRN R3 +00000011 +10000010 # LDI R2,TEST5 +00000010 +01001001 +01010100 # JMP R2 +00000010 +01000111 # PRN R3 +00000011 +# TEST5 (address 73): +00000001 # HLT From f42dbc97d5584ea0d2175638c95a3e420a798677 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Fri, 8 Mar 2019 11:54:36 -0500 Subject: [PATCH 17/19] refactors to utilize ALU and cleans up cpu_run --- ls8/cpu.c | 66 ++++++++++++++++++++----------------------------------- ls8/cpu.h | 2 ++ 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 132fb43a..f1960d5f 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -53,8 +53,27 @@ void cpu_load(struct cpu *cpu, char *file) void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { switch (op) { + case ALU_ADD: + cpu->registers[regA] += cpu->registers[regB]; + break; + case ALU_CMP: + if (cpu->registers[regA] == cpu->registers[regB]) + { + cpu->E = 1; + break; + } + else if (cpu->registers[regA] > cpu->registers[regB]) + { + cpu->G = 1; + break; + } + else + { + cpu->L = 1; + break; + } case ALU_MUL: - // TODO + cpu->registers[regA] *= cpu->registers[regB]; break; // TODO: implement more ALU ops @@ -93,10 +112,8 @@ void cpu_run(struct cpu *cpu) switch (ir) { case ADD: - { - cpu->registers[operandA] += cpu->registers[operandB]; + alu(cpu, ALU_ADD, operandA, operandB); break; - } case CALL: cpu->ram[--cpu->registers[7]] = cpu->PC + next_line; cpu->PC = cpu->registers[operandA]; @@ -105,81 +122,46 @@ void cpu_run(struct cpu *cpu) cpu->PC = cpu->ram[cpu->registers[7]++]; continue; case CMP: - { - if (cpu->registers[operandA] == cpu->registers[operandB]) - { - cpu->E = 1; - break; - } - else if (cpu->registers[operandA] > cpu->registers[operandB]) - { - cpu->G = 1; - break; - } - else - { - cpu->L = 1; - break; - } - } + alu(cpu, ALU_CMP, operandA, operandB); + break; case HLT: - { running = 0; break; - } case JEQ: - { if (cpu->E == 1) { cpu->PC = cpu->registers[operandA]; continue; } break; - } case JMP: - { cpu->PC = cpu->registers[operandA]; continue; - } case JNE: - { if (cpu->E != 1) { cpu->PC = cpu->registers[operandA]; continue; } break; - } case LDI: - { cpu->registers[operandA] = operandB; break; - } case MUL: - { - cpu->registers[operandA] *= cpu->registers[operandB]; + alu(cpu, ALU_MUL, operandA, operandB); break; - } case POP: - { cpu->registers[operandA] = cpu_ram_read(cpu, cpu->registers[7]); cpu->ram[cpu->registers[7]++] = 0x00; break; - } case PRN: - { printf("%d\n", cpu->registers[operandA]); break; - } case PUSH: - { cpu_ram_write(cpu, --cpu->registers[7], cpu->registers[operandA]); break; - } default: - { break; - } } cpu->PC = cpu->PC + next_line; // 5. Do whatever the instruction should do according to the spec. diff --git a/ls8/cpu.h b/ls8/cpu.h index 365b492f..395d36f8 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -18,6 +18,8 @@ struct cpu { // ALU operations enum alu_op { + ALU_ADD, + ALU_CMP, ALU_MUL // Add more here }; From 39818f5f6f0f954b9e3c994428220c7791320b8d Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Fri, 8 Mar 2019 12:02:11 -0500 Subject: [PATCH 18/19] cleans up comments and printfs for debugging --- ls8/cpu.c | 33 ++++----------------------------- ls8/cpu.h | 17 +---------------- 2 files changed, 5 insertions(+), 45 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index f1960d5f..fadc6e28 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -2,7 +2,6 @@ #include #include #include -#define DATA_LEN 6 unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) { @@ -13,13 +12,8 @@ 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 *file) { - FILE *fp; char line[1024]; @@ -38,18 +32,13 @@ void cpu_load(struct cpu *cpu, char *file) value = strtoul(line, &endptr, 2); if(endptr == line){ - // printf("Ignoring this line.\n"); continue; } - // printf("'line' - %s\n'value' - %d\n'address' - %d", line, value, address); cpu->ram[address++] = value; } } -/** - * ALU - */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { switch (op) { @@ -75,24 +64,15 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB case ALU_MUL: cpu->registers[regA] *= cpu->registers[regB]; break; - - // TODO: implement more ALU ops } } -/** - * Run the CPU - */ void cpu_run(struct cpu *cpu) { - int running = 1; // True until we get a HLT instruction - // printf("in run"); + int running = 1; + 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 - // 3. Get the appropriate value(s) of the operands following this instruction unsigned char operandA; unsigned char operandB; int next_line = 1; @@ -108,7 +88,7 @@ void cpu_run(struct cpu *cpu) operandA = cpu->ram[(cpu->PC + 1) & 0xff]; next_line = 2; } - // 4. switch() over it to decide on a course of action. + switch (ir) { case ADD: @@ -164,14 +144,9 @@ void cpu_run(struct cpu *cpu) break; } cpu->PC = cpu->PC + next_line; - // 5. Do whatever the instruction should do according to the spec. - // 6. Move the PC to the next instruction. } } -/** - * Initialize a CPU struct - */ void cpu_init(struct cpu *cpu) { cpu->PC = 0; @@ -182,4 +157,4 @@ void cpu_init(struct cpu *cpu) memset(cpu->ram, 0, 8 * sizeof(unsigned char)); memset(cpu->registers, 0, 256 * sizeof(unsigned char)); cpu->registers[7] = 0xF4; -} +} \ No newline at end of file diff --git a/ls8/cpu.h b/ls8/cpu.h index 395d36f8..68a9e4f5 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -1,34 +1,22 @@ #ifndef _CPU_H_ #define _CPU_H_ -// Holds all information about the CPU struct cpu { - // TODO - // PC unsigned char PC; unsigned char FL; unsigned char E; unsigned char L; unsigned char G; - // registers (array) unsigned char registers[8]; - // ram (array) unsigned char ram[256]; }; -// ALU operations enum alu_op { ALU_ADD, ALU_CMP, ALU_MUL - // Add more here }; -// Instructions - -// 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 @@ -42,12 +30,9 @@ enum alu_op { #define JEQ 0b01010101 #define JMP 0b01010100 #define JNE 0b01010110 -// TODO: more instructions here. These can be used in cpu_run(). - -// Function declarations extern void cpu_load(struct cpu *cpu, char *file); extern void cpu_init(struct cpu *cpu); extern void cpu_run(struct cpu *cpu); -#endif +#endif \ No newline at end of file From 51be7b5db90a81b0792e7f0a9d0d0273baa7dd59 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Fri, 8 Mar 2019 13:17:16 -0500 Subject: [PATCH 19/19] adds AND, OR, XOR, NOT, SHL, SHR, and MOD operations --- ls8/cpu.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ls8/cpu.h | 31 +++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index fadc6e28..160a9864 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -45,6 +45,9 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB case ALU_ADD: cpu->registers[regA] += cpu->registers[regB]; break; + case ALU_AND: + cpu->registers[regA] = cpu->registers[regA] & cpu->registers[regB]; + break; case ALU_CMP: if (cpu->registers[regA] == cpu->registers[regB]) { @@ -61,9 +64,27 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB cpu->L = 1; break; } + case ALU_MOD: + cpu->registers[regA] %= cpu->registers[regB]; + break; case ALU_MUL: cpu->registers[regA] *= cpu->registers[regB]; break; + case ALU_NOT: + cpu->registers[regA] = ~cpu->registers[regA]; + break; + case ALU_OR: + cpu->registers[regA] = cpu->registers[regA] | cpu->registers[regB]; + break; + case ALU_SHL: + cpu->registers[regA] = cpu->registers[regA] << cpu->registers[regB]; + break; + case ALU_SHR: + cpu->registers[regA] = cpu->registers[regA] >> cpu->registers[regB]; + break; + case ALU_XOR: + cpu->registers[regA] = cpu->registers[regA] ^ cpu->registers[regB]; + break; } } @@ -94,6 +115,9 @@ void cpu_run(struct cpu *cpu) case ADD: alu(cpu, ALU_ADD, operandA, operandB); break; + case AND: + alu(cpu, ALU_AND, operandA, operandB); + break; case CALL: cpu->ram[--cpu->registers[7]] = cpu->PC + next_line; cpu->PC = cpu->registers[operandA]; @@ -127,9 +151,26 @@ void cpu_run(struct cpu *cpu) case LDI: cpu->registers[operandA] = operandB; break; + case MOD: + if (cpu->registers[operandB] == 0) + { + printf("Dividing by zero is not allowed.\n"); + running = 0; + } + else + { + alu(cpu, ALU_MOD, operandA, operandB); + } + break; case MUL: alu(cpu, ALU_MUL, operandA, operandB); break; + case NOT: + alu(cpu, ALU_AND, operandA, operandB); + break; + case OR: + alu(cpu, ALU_AND, operandA, operandB); + break; case POP: cpu->registers[operandA] = cpu_ram_read(cpu, cpu->registers[7]); cpu->ram[cpu->registers[7]++] = 0x00; @@ -140,6 +181,18 @@ void cpu_run(struct cpu *cpu) case PUSH: cpu_ram_write(cpu, --cpu->registers[7], cpu->registers[operandA]); break; + case SHL: + alu(cpu, ALU_SHL, operandA, operandB); + break; + case SHR: + alu(cpu, ALU_SHR, operandA, operandB); + break; + case ST: + cpu_ram_write(cpu, operandA, cpu->registers[operandB]); + break; + case XOR: + alu(cpu, ALU_AND, operandA, operandB); + break; default: break; } diff --git a/ls8/cpu.h b/ls8/cpu.h index 68a9e4f5..770f64ef 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -13,23 +13,38 @@ struct cpu { enum alu_op { ALU_ADD, + ALU_AND, ALU_CMP, - ALU_MUL + ALU_MOD, + ALU_MUL, + ALU_NOT, + ALU_OR, + ALU_SHL, + ALU_SHR, + ALU_XOR }; -#define LDI 0b10000010 -#define HLT 0b00000001 -#define PRN 0b01000111 -#define MUL 0b10100010 -#define POP 0b01000110 -#define PUSH 0b01000101 #define ADD 0b10100000 +#define AND 0b10101000 #define CALL 0b01010000 -#define RET 0b00010001 #define CMP 0b10100111 +#define HLT 0b00000001 #define JEQ 0b01010101 #define JMP 0b01010100 #define JNE 0b01010110 +#define LDI 0b10000010 +#define MOD 0b10100100 +#define MUL 0b10100010 +#define NOT 0b01101001 +#define OR 0b10101010 +#define POP 0b01000110 +#define PRN 0b01000111 +#define PUSH 0b01000101 +#define RET 0b00010001 +#define SHL 0b10101100 +#define SHR 0b10101101 +#define ST 0b10000100 +#define XOR 0b10101011 extern void cpu_load(struct cpu *cpu, char *file); extern void cpu_init(struct cpu *cpu);