From 287fc67562acc8049d5dec9188f37e9e751e9619 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Mon, 4 Mar 2019 13:56:30 -0700 Subject: [PATCH 01/21] Ian Cameron Computer Architecture --- ls8/cpu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..9e16e8a1 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -5,6 +5,7 @@ struct cpu { // TODO // PC + unsigned int *pc; // registers (array) // ram (array) }; From d0750f8c7bd81f4dd545d6a73464fcbda7179f84 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Mon, 4 Mar 2019 15:38:59 -0700 Subject: [PATCH 02/21] adds cpu struct and init --- ls8/cpu.c | 3 +++ ls8/cpu.h | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..b8162e51 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -64,4 +64,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->reg, 0, sizeof(unsigned char)*8); //just use size of cpu reg? + memset(cpu->ram, 0, sizeof(unsigned char)*256); } diff --git a/ls8/cpu.h b/ls8/cpu.h index 9e16e8a1..b1197bd5 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -2,13 +2,15 @@ #define _CPU_H_ // Holds all information about the CPU -struct cpu { +typedef struct cpu { // TODO // PC - unsigned int *pc; + unsigned char pc; // registers (array) + unsigned char reg[8]; // ram (array) -}; + unsigned char ram[256] +} cpu; // ALU operations enum alu_op { From aaecaf7395f380bbc87d3786ea91a10494ecc76b Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Mon, 4 Mar 2019 16:32:54 -0700 Subject: [PATCH 03/21] adds read and write --- ls8/cpu.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index b8162e51..9d0f7735 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -40,6 +40,17 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB } } +unsigned char read_ram(struct cpu *cpu, unsigned char address) +{ + return cpu->ram[address]; +} + +//set value at address in ram to new value +void ram_write(struct cpu *cpu, unsigned char address, unsigned char value) +{ + cpu->ram[address] = value; +} + /** * Run the CPU */ From d0c1fe03ba156391307a492c81a567792e6b8a29 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Tue, 5 Mar 2019 13:36:25 -0700 Subject: [PATCH 04/21] adds run --- ls8/cpu.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 9d0f7735..db9589e9 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,3 +1,7 @@ +#include +#include +#include //need for printf + #include "cpu.h" #define DATA_LEN 6 @@ -40,13 +44,13 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB } } -unsigned char read_ram(struct cpu *cpu, unsigned char address) +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) { return cpu->ram[address]; } -//set value at address in ram to new value -void ram_write(struct cpu *cpu, unsigned char address, unsigned char value) +//address is index in ram so set to new value +void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) { cpu->ram[address] = value; } @@ -61,10 +65,32 @@ 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); + printf("TRACE: %0X2: %0X2 %0X2 %0X2 \n", cpu->pc, IR, operandA, operandB); // 4. switch() over it to decide on a course of action. // 5. Do whatever the instruction should do according to the spec. + switch(IR) + { + case LDI: + cpu->reg[operandA] = operandB; + //increment by 3 since 3 arguments (CP+2) + cpu->pc += 3; + break; + case PRN: + printf("%d\n", cpu->reg[operandA]); + cpu->pc += 2; + break; + case HLT: + running = 0; + break; + default: + printf("unexpected instruction: 0x%0X2 at 0x%0X2 \n", IR, cpu->pc); + exit(1); + } // 6. Move the PC to the next instruction. } } @@ -79,3 +105,9 @@ void cpu_init(struct cpu *cpu) memset(cpu->reg, 0, sizeof(unsigned char)*8); //just use size of cpu reg? memset(cpu->ram, 0, sizeof(unsigned char)*256); } +// When the LS-8 is booted, the following steps occur: + +// * `R0`-`R6` are cleared to `0`. +// * `R7` is set to `0xF4`. +// * `PC` and `FL` registers are cleared to `0`. +// * RAM is cleared to `0`. \ No newline at end of file From a79038f36d59cb37f52807d9e39e08b8c452a8c7 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Tue, 5 Mar 2019 15:29:55 -0700 Subject: [PATCH 05/21] starts cpu load --- ls8/cpu.c | 61 +++++++++++++++++++++++++++++++++++-------------------- ls8/cpu.h | 3 ++- ls8/ls8.c | 8 ++++++-- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index db9589e9..033ca208 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -11,22 +11,37 @@ */ 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 - }; - - int address = 0; - - for (int i = 0; i < DATA_LEN; i++) { - cpu->ram[address++] = data[i]; + //open file + FILE *fptr = fopen("", "r") + + //read line by line until returns null, ignore blank lines and comments + while(fgets() != NULL) + { + } + //save data into ram, have to convert binary strings to int values to store in ram with strtoul + + + fclose(fptr); + + //original hard code we're refactoring + // char data[DATA_LEN] = { + // // 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++) { + // cpu->ram[address++] = data[i]; + // } + // TODO: Replace this with something less hard-coded } @@ -44,15 +59,15 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB } } -unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char mar) { - return cpu->ram[address]; + return cpu->ram[mar]; } -//address is index in ram so set to new value -void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) +//mar is index in ram so set to new value +void cpu_ram_write(struct cpu *cpu, unsigned char mar, unsigned char mdr) { - cpu->ram[address] = value; + cpu->ram[mar] = mdr; } /** @@ -76,18 +91,20 @@ void cpu_run(struct cpu *cpu) switch(IR) { case LDI: + //sets value in given register to value specified cpu->reg[operandA] = operandB; //increment by 3 since 3 arguments (CP+2) cpu->pc += 3; break; case PRN: + //print out numerically in given register printf("%d\n", cpu->reg[operandA]); cpu->pc += 2; break; - case HLT: - running = 0; + case HLT: //why is this needed when have break ? + running = 0; //set running to false break; - default: + default: //program stops if gets instruction it doesnt know printf("unexpected instruction: 0x%0X2 at 0x%0X2 \n", IR, cpu->pc); exit(1); } diff --git a/ls8/cpu.h b/ls8/cpu.h index b1197bd5..3db8593a 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -6,10 +6,11 @@ typedef struct cpu { // TODO // PC unsigned char pc; + unsigned char fl; // registers (array) unsigned char reg[8]; // ram (array) - unsigned char ram[256] + unsigned char ram[256]; } cpu; // ALU operations diff --git a/ls8/ls8.c b/ls8/ls8.c index d24578ee..bb31626c 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,7 +4,8 @@ /** * Main */ -int main(void) +//the way this is set up shows us the order that this should be built out +int main(int argc, char *argv[]) //changed from void for command line processing. arg count and array of strings that hold indiv args. { struct cpu cpu; @@ -13,4 +14,7 @@ int main(void) cpu_run(&cpu); return 0; -} \ No newline at end of file +} + +//argv[0] == "./ls8" +//argv[1] == "examples/mult.ls8" \ No newline at end of file From 8b121c84dd71aa0cb2c7f4beaf71e7cafd78e46d Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Tue, 5 Mar 2019 16:41:47 -0700 Subject: [PATCH 06/21] adds load --- ls8/cpu.c | 30 ++++++++++++++++++++++-------- ls8/cpu.h | 2 +- ls8/ls8.c | 11 ++++++++++- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 033ca208..4ee5bd79 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,6 +1,6 @@ #include #include -#include //need for printf +#include #include "cpu.h" @@ -9,20 +9,34 @@ /** * 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 *filename) { //open file - FILE *fptr = fopen("", "r") + FILE *fptr = fopen("filename", "r"); - //read line by line until returns null, ignore blank lines and comments - while(fgets() != NULL) + if (fptr == NULL) { - + printf("File %s is not recognized.\n", filename); + exit(2); } - //save data into ram, have to convert binary strings to int values to store in ram with strtoul + //read line by line until returns null, ignore blank lines and comments + char line[1000]; + int address = 0; + while(fgets(line, sizeof line, fptr) != NULL) + { + char *endpointer; + unsigned char value = strtoul(line, endpointer, 2); + if (endpointer == NULL) + { + continue; + } + //save data into ram, have to convert binary strings to int values to store in ram with strtoul + //cpu_ram_write(cpu, address++, value); + cpu->ram[address++] = value; + } fclose(fptr); //original hard code we're refactoring @@ -85,7 +99,7 @@ void cpu_run(struct cpu *cpu) // 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); - printf("TRACE: %0X2: %0X2 %0X2 %0X2 \n", cpu->pc, IR, operandA, operandB); + printf("TRACE: %02X: %02X %02X %02X \n", cpu->pc, IR, operandA, operandB); // 4. switch() over it to decide on a course of action. // 5. Do whatever the instruction should do according to the spec. switch(IR) diff --git a/ls8/cpu.h b/ls8/cpu.h index 3db8593a..db750a56 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -31,7 +31,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 bb31626c..bb771b03 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -9,12 +9,21 @@ int main(int argc, char *argv[]) //changed from void for command line processing { struct cpu cpu; + if (argc != 2) + { + fprintf(stderr, "This function requires two arguments."); + return 1; //same as exit(1) + } + + char *filename = argv[1]; + cpu_init(&cpu); - cpu_load(&cpu); + cpu_load(&cpu, filename); //also update prototype to include char pointer cpu_run(&cpu); return 0; } + //argv[0] == "./ls8" //argv[1] == "examples/mult.ls8" \ No newline at end of file From 302b85d39ed080bccd5fb2ab36fce29c2c051767 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Tue, 5 Mar 2019 22:26:20 -0700 Subject: [PATCH 07/21] adds mult and add --- ls8/cpu.c | 15 +++++++++++++-- ls8/cpu.h | 5 ++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 4ee5bd79..f00bf6d9 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -27,7 +27,7 @@ void cpu_load(struct cpu *cpu, char *filename) while(fgets(line, sizeof line, fptr) != NULL) { char *endpointer; - unsigned char value = strtoul(line, endpointer, 2); + unsigned char value = strtoul(line, &endpointer, 2); if (endpointer == NULL) { @@ -67,9 +67,12 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB switch (op) { case ALU_MUL: // TODO + cpu->reg[regA] = cpu->reg[regA]*cpu->reg[regB]; break; - // TODO: implement more ALU ops + case ALU_ADD: + cpu->reg[regA] = cpu->reg[regA]+cpu->reg[regB]; + break; } } @@ -115,6 +118,14 @@ void cpu_run(struct cpu *cpu) printf("%d\n", cpu->reg[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; case HLT: //why is this needed when have break ? running = 0; //set running to false break; diff --git a/ls8/cpu.h b/ls8/cpu.h index db750a56..611e82d7 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -15,7 +15,8 @@ typedef struct cpu { // ALU operations enum alu_op { - ALU_MUL + ALU_MUL, + ALU_ADD // Add more here }; @@ -28,6 +29,8 @@ enum alu_op { #define HLT 0b00000001 #define PRN 0b01000111 // TODO: more instructions here. These can be used in cpu_run(). +#define MUL 0b10100010 +#define ADD 0b10100000 // Function declarations From 50fac77ff089a6ea8696a966c6a05ebe7eb8aaa8 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Wed, 6 Mar 2019 13:13:14 -0700 Subject: [PATCH 08/21] wed --- ls8/cpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ls8/cpu.h b/ls8/cpu.h index 611e82d7..811b029e 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -21,6 +21,8 @@ enum alu_op { }; // Instructions +//memory locations !!!!!!!!!!!!!!!!! + // These use binary literals. If these aren't available with your compiler, hex // literals should be used. From 261f11c4b19e2323b0192b3f2e26e6d4118ffd18 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Wed, 6 Mar 2019 13:39:20 -0700 Subject: [PATCH 09/21] debugged load --- ls8/cpu.c | 16 +++++++++------- ls8/cpu.h | 1 + ls8/ls8.c | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index f00bf6d9..c9fb1b39 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -12,7 +12,7 @@ void cpu_load(struct cpu *cpu, char *filename) { //open file - FILE *fptr = fopen("filename", "r"); + FILE *fptr = fopen(filename, "r"); if (fptr == NULL) { @@ -26,10 +26,11 @@ void cpu_load(struct cpu *cpu, char *filename) while(fgets(line, sizeof line, fptr) != NULL) { + //convert string to a number. if get an error char *endpointer; - unsigned char value = strtoul(line, &endpointer, 2); - - if (endpointer == NULL) + unsigned char value = strtoul(line, &endpointer, 2); //needs pointer to a pointer so need & as address of pointer + //ignore lines where no numbers read + if (endpointer == NULL) //endpointer == line?? { continue; } @@ -67,7 +68,7 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB switch (op) { case ALU_MUL: // TODO - cpu->reg[regA] = cpu->reg[regA]*cpu->reg[regB]; + cpu->reg[regA] = cpu->reg[regA]*cpu->reg[regB]; //reg[regA] *= valB?? break; // TODO: implement more ALU ops case ALU_ADD: @@ -144,8 +145,9 @@ void cpu_init(struct cpu *cpu) { // TODO: Initialize the PC and other special registers cpu->pc = 0; - memset(cpu->reg, 0, sizeof(unsigned char)*8); //just use size of cpu reg? - memset(cpu->ram, 0, sizeof(unsigned char)*256); + memset(cpu->reg, 0, sizeof cpu->reg); //R7?????? + cpu->reg[7] = 0xf4; + memset(cpu->ram, 0, sizeof cpu->ram); } // When the LS-8 is booted, the following steps occur: diff --git a/ls8/cpu.h b/ls8/cpu.h index 811b029e..f480dce2 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -22,6 +22,7 @@ enum alu_op { // Instructions //memory locations !!!!!!!!!!!!!!!!! +#define ADD_EMPTY_STACK 0xf4 // These use binary literals. If these aren't available with your compiler, hex diff --git a/ls8/ls8.c b/ls8/ls8.c index bb771b03..1553d4d2 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) //changed from void for command line processing if (argc != 2) { fprintf(stderr, "This function requires two arguments."); - return 1; //same as exit(1) + return 1; //same as exit(1) b/c normally return 0 } char *filename = argv[1]; From ee7eb8f90ff22c95d592396ddf7ef7976b51a4a7 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Wed, 6 Mar 2019 15:31:41 -0700 Subject: [PATCH 10/21] adds push --- ls8/cpu.c | 15 ++++++++++++++- ls8/cpu.h | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index c9fb1b39..e81a7924 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -88,6 +88,15 @@ void cpu_ram_write(struct cpu *cpu, unsigned char mar, unsigned char mdr) cpu->ram[mar] = mdr; } +void push(struct cpu *cpu, unsigned char val) +{ + //push the value in the given register to top of the stack + //decrement the sp + cpu->reg[7]--; + //copy the value in the given register to the address pointed to by the sp + cpu_ram_write(cpu, cpu->reg[7], cpu->reg[val]); +} + /** * Run the CPU */ @@ -127,7 +136,11 @@ void cpu_run(struct cpu *cpu) alu(cpu, ALU_ADD, operandA, operandB); cpu->pc += 3; break; - case HLT: //why is this needed when have break ? + case PUSH: + push(cpu, operandA); + cpu->pc += 2; + break; + case HLT: running = 0; //set running to false break; default: //program stops if gets instruction it doesnt know diff --git a/ls8/cpu.h b/ls8/cpu.h index f480dce2..ebddfa5f 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -23,6 +23,7 @@ enum alu_op { // Instructions //memory locations !!!!!!!!!!!!!!!!! #define ADD_EMPTY_STACK 0xf4 +#define ADD_PROGRAM_ENTRY 0x00 // These use binary literals. If these aren't available with your compiler, hex @@ -34,6 +35,8 @@ enum alu_op { // TODO: more instructions here. These can be used in cpu_run(). #define MUL 0b10100010 #define ADD 0b10100000 +#define PUSH 0b01000101 +#define POP 0b01000110 // Function declarations From fb8f3c82b090545e0530a0b3a8a27b350cce495f Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Wed, 6 Mar 2019 21:46:10 -0700 Subject: [PATCH 11/21] adds pop --- ls8/cpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index e81a7924..6e2575dc 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -94,9 +94,19 @@ void push(struct cpu *cpu, unsigned char val) //decrement the sp cpu->reg[7]--; //copy the value in the given register to the address pointed to by the sp + //another variable? add sp to struct? cpu_ram_write(cpu, cpu->reg[7], cpu->reg[val]); } +void pop(struct cpu *cpu, unsigned char val) +{ + //pop the value at the top of the stack into given register + //copy the value from the address pointed to by sp to given register + cpu->reg[val] = cpu_ram_read(cpu, cpu->reg[7]); + //increment sp + cpu->reg[7]++; +} + /** * Run the CPU */ @@ -140,6 +150,10 @@ void cpu_run(struct cpu *cpu) push(cpu, operandA); cpu->pc += 2; break; + case POP: + pop(cpu, operandA); + cpu->pc += 2; + break; case HLT: running = 0; //set running to false break; From c234c3fe8dbe6c9eb1b882a29ad1e716d0275f20 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Thu, 7 Mar 2019 13:56:52 -0700 Subject: [PATCH 12/21] starts call --- ls8/cpu.c | 19 ++++++++++++++++++- ls8/cpu.h | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 6e2575dc..74282e41 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -102,11 +102,25 @@ void pop(struct cpu *cpu, unsigned char val) { //pop the value at the top of the stack into given register //copy the value from the address pointed to by sp to given register + //put value in register take it out of ram (by reading) get address reg7 and store it in given register cpu->reg[val] = cpu_ram_read(cpu, cpu->reg[7]); //increment sp cpu->reg[7]++; } +void call(struct cpu *cpu, unsigned char registerAddress) +{ + //push address of instruction on to stack so we can return to where we left off after subroutine executes + unsigned char address = cpu->reg[registerAddress]; + //stack grows down so make room on stack to store address + cpu->reg[7]--; + //add return location to stack. + cpu->ram[cpu->reg[7]]; + //set program counter to location of subroutine + cpu->pc = address; + //pc is set to address stored in given register. jump to that location and execute the instruction in the subroutine. +} + /** * Run the CPU */ @@ -154,6 +168,10 @@ void cpu_run(struct cpu *cpu) pop(cpu, operandA); cpu->pc += 2; break; + case CALL: + call(cpu, operandA); + cpu->pc += 2; + break; case HLT: running = 0; //set running to false break; @@ -177,7 +195,6 @@ void cpu_init(struct cpu *cpu) memset(cpu->ram, 0, sizeof cpu->ram); } // When the LS-8 is booted, the following steps occur: - // * `R0`-`R6` are cleared to `0`. // * `R7` is set to `0xF4`. // * `PC` and `FL` registers are cleared to `0`. diff --git a/ls8/cpu.h b/ls8/cpu.h index ebddfa5f..548b8b0e 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -37,6 +37,8 @@ enum alu_op { #define ADD 0b10100000 #define PUSH 0b01000101 #define POP 0b01000110 +#define CALL 0b01010000 +#define RET 0b00010001 // Function declarations From 108696086ccd04a54f219bd60b4cc48e06bbf266 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Thu, 7 Mar 2019 15:24:56 -0700 Subject: [PATCH 13/21] adds call --- ls8/cpu.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 74282e41..cc926c99 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -95,32 +95,36 @@ void push(struct cpu *cpu, unsigned char val) cpu->reg[7]--; //copy the value in the given register to the address pointed to by the sp //another variable? add sp to struct? - cpu_ram_write(cpu, cpu->reg[7], cpu->reg[val]); + cpu_ram_write(cpu, cpu->reg[7], val); } -void pop(struct cpu *cpu, unsigned char val) +unsigned char pop(struct cpu *cpu) { //pop the value at the top of the stack into given register //copy the value from the address pointed to by sp to given register //put value in register take it out of ram (by reading) get address reg7 and store it in given register - cpu->reg[val] = cpu_ram_read(cpu, cpu->reg[7]); + //unsigned char pop_val = cpu_ram_read(cpu, cpu->reg[7]); + unsigned char val = cpu->ram[cpu->reg[7]]; //increment sp - cpu->reg[7]++; + cpu->reg[7]++; + return val; } void call(struct cpu *cpu, unsigned char registerAddress) { //push address of instruction on to stack so we can return to where we left off after subroutine executes unsigned char address = cpu->reg[registerAddress]; - //stack grows down so make room on stack to store address - cpu->reg[7]--; - //add return location to stack. - cpu->ram[cpu->reg[7]]; + push(cpu, cpu->pc+2); //set program counter to location of subroutine cpu->pc = address; //pc is set to address stored in given register. jump to that location and execute the instruction in the subroutine. } +void ret(struct cpu *cpu) +{ + cpu->pc = pop(cpu); +} + /** * Run the CPU */ @@ -161,16 +165,18 @@ void cpu_run(struct cpu *cpu) cpu->pc += 3; break; case PUSH: - push(cpu, operandA); + push(cpu, cpu->reg[operandA]); cpu->pc += 2; break; case POP: - pop(cpu, operandA); + cpu->reg[operandA] = pop(cpu); cpu->pc += 2; break; case CALL: call(cpu, operandA); - cpu->pc += 2; + break; + case RET: + ret(cpu); break; case HLT: running = 0; //set running to false From 2c3d2939cf9567dbcd231ea45d712912b9a70fa0 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Thu, 7 Mar 2019 16:03:04 -0700 Subject: [PATCH 14/21] starts return --- ls8/cpu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index cc926c99..d75bfeb5 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -122,6 +122,7 @@ void call(struct cpu *cpu, unsigned char registerAddress) void ret(struct cpu *cpu) { + //return from subroutine. pop value from top of stack and store in pc. cpu->pc = pop(cpu); } @@ -143,6 +144,7 @@ void cpu_run(struct cpu *cpu) printf("TRACE: %02X: %02X %02X %02X \n", cpu->pc, IR, operandA, operandB); // 4. switch() over it to decide on a course of action. // 5. Do whatever the instruction should do according to the spec. + //int instruction_set_pc = (IR >> 4); switch(IR) { case LDI: @@ -186,6 +188,10 @@ void cpu_run(struct cpu *cpu) exit(1); } // 6. Move the PC to the next instruction. + // if (!instruction_set_pc) + // { + // cpu->pc+= ((IR >> 6) & 0x3) + 1; + // } } } From 88479e027e4cd4db7da18dfc6cbd7df44f8bc28b Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Thu, 7 Mar 2019 17:16:42 -0700 Subject: [PATCH 15/21] adds return --- ls8/cpu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index d75bfeb5..9b7d4361 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -137,6 +137,7 @@ 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); + printf("IR is here 0x%02X\n", IR); // 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); @@ -163,6 +164,7 @@ void cpu_run(struct cpu *cpu) cpu->pc += 3; break; case ADD: + printf("got here\n"); alu(cpu, ALU_ADD, operandA, operandB); cpu->pc += 3; break; @@ -175,10 +177,14 @@ void cpu_run(struct cpu *cpu) cpu->pc += 2; break; case CALL: - call(cpu, operandA); + //call(cpu, operandA); + push(cpu, cpu->pc + 2); + cpu->pc = cpu->reg[operandA]; + printf("TRACE: 0x%02X\n", cpu->pc); break; case RET: - ret(cpu); + //ret(cpu); + cpu->pc = pop(cpu); break; case HLT: running = 0; //set running to false From a5895f68a54fd94627a61c1405806823cea3204d Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Thu, 7 Mar 2019 17:25:02 -0700 Subject: [PATCH 16/21] debugs endpointer line call working --- ls8/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 9b7d4361..434f90bf 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -30,7 +30,7 @@ void cpu_load(struct cpu *cpu, char *filename) char *endpointer; unsigned char value = strtoul(line, &endpointer, 2); //needs pointer to a pointer so need & as address of pointer //ignore lines where no numbers read - if (endpointer == NULL) //endpointer == line?? + if (endpointer == line) { continue; } From 15ed117d9ce8818db5563d42590c05995512f9d9 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Fri, 8 Mar 2019 09:11:31 -0700 Subject: [PATCH 17/21] initial sprint commit --- ls8/cpu.c | 1 + ls8/cpu.h | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 434f90bf..2b525094 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -207,6 +207,7 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { // TODO: Initialize the PC and other special registers + cpu->fl = 0; cpu->pc = 0; memset(cpu->reg, 0, sizeof cpu->reg); //R7?????? cpu->reg[7] = 0xf4; diff --git a/ls8/cpu.h b/ls8/cpu.h index 548b8b0e..f9c3ed6e 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -13,15 +13,18 @@ typedef struct cpu { unsigned char ram[256]; } cpu; +//add flag somewhere else below? instructions? + // ALU operations enum alu_op { ALU_MUL, - ALU_ADD + ALU_ADD, + ALU_CMP // Add more here }; // Instructions -//memory locations !!!!!!!!!!!!!!!!! +//memory locations !!!!!!!!!!!!!!!!! #define ADD_EMPTY_STACK 0xf4 #define ADD_PROGRAM_ENTRY 0x00 From 46b9de5a454fb259624b50858872ae49351e0cc9 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Fri, 8 Mar 2019 09:57:18 -0700 Subject: [PATCH 18/21] adds cmp --- ls8/cpu.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/ls8/cpu.c b/ls8/cpu.c index 2b525094..283fb9de 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -65,6 +65,9 @@ void cpu_load(struct cpu *cpu, char *filename) */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { + unsigned char valA = cpu->reg[regA]; + unsigned char valB = cpu->reg[regB]; + unsigned char flag; switch (op) { case ALU_MUL: // TODO @@ -74,6 +77,25 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB case ALU_ADD: cpu->reg[regA] = cpu->reg[regA]+cpu->reg[regB]; break; + case ALU_CMP: + if (valA < valB) + { + flag = 0b00000100; + } + else if (valA > valB) + { + flag = 0b00000010; + } + else if (valA == valB) + { + flag = 0b00000001; + } + else + { + flag = 0b00000000; + } + cpu->fl = flag; + break; } } @@ -186,6 +208,9 @@ void cpu_run(struct cpu *cpu) //ret(cpu); cpu->pc = pop(cpu); break; + case CMP: + alu(cpu, ALU_CMP, operandA, operandB); + break; case HLT: running = 0; //set running to false break; From 8fb1232af0e5ea7a5fd2720d490992c4cbd786c0 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Fri, 8 Mar 2019 10:31:17 -0700 Subject: [PATCH 19/21] adds jmp --- ls8/cpu.c | 7 ++++--- ls8/cpu.h | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 283fb9de..6cc60a0a 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -159,7 +159,6 @@ 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); - printf("IR is here 0x%02X\n", IR); // 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); @@ -186,7 +185,6 @@ void cpu_run(struct cpu *cpu) cpu->pc += 3; break; case ADD: - printf("got here\n"); alu(cpu, ALU_ADD, operandA, operandB); cpu->pc += 3; break; @@ -202,7 +200,7 @@ void cpu_run(struct cpu *cpu) //call(cpu, operandA); push(cpu, cpu->pc + 2); cpu->pc = cpu->reg[operandA]; - printf("TRACE: 0x%02X\n", cpu->pc); + //printf("TRACE: 0x%02X\n", cpu->pc); break; case RET: //ret(cpu); @@ -211,6 +209,9 @@ void cpu_run(struct cpu *cpu) case CMP: alu(cpu, ALU_CMP, operandA, operandB); break; + case JMP: + cpu->pc = cpu->reg[operandA]; + break; case HLT: running = 0; //set running to false break; diff --git a/ls8/cpu.h b/ls8/cpu.h index f9c3ed6e..72f0864c 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -19,7 +19,7 @@ typedef struct cpu { enum alu_op { ALU_MUL, ALU_ADD, - ALU_CMP + ALU_CMP, // Add more here }; @@ -42,6 +42,8 @@ enum alu_op { #define POP 0b01000110 #define CALL 0b01010000 #define RET 0b00010001 +#define CMP 0b10100111 +#define JMP 0b01010100 // Function declarations From 62cec8afa886457af64d52b8f8904bff084cd503 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Fri, 8 Mar 2019 10:47:56 -0700 Subject: [PATCH 20/21] adds jeq --- ls8/cpu.c | 19 +++++++++++++------ ls8/cpu.h | 2 ++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index 6cc60a0a..41c1e6f8 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -77,22 +77,22 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB case ALU_ADD: cpu->reg[regA] = cpu->reg[regA]+cpu->reg[regB]; break; - case ALU_CMP: - if (valA < valB) + case ALU_CMP: //compare values in two registers w limited subtraction. + if (valA < valB) //if less than flag to 1 { - flag = 0b00000100; + flag = 0b00000100; } - else if (valA > valB) + else if (valA > valB) //if greater than flag to 1 { flag = 0b00000010; } - else if (valA == valB) + else if (valA == valB) //if equal flag to 1 { flag = 0b00000001; } else { - flag = 0b00000000; + flag = 0b00000000; //otherwise set to 0 } cpu->fl = flag; break; @@ -210,8 +210,15 @@ void cpu_run(struct cpu *cpu) alu(cpu, ALU_CMP, operandA, operandB); break; case JMP: + //jump to address stored in given register. set pc to address stored in given register. cpu->pc = cpu->reg[operandA]; break; + case JEQ: + //if equal flag set to true jump to address stored at given register. + if (cpu->fl == 1) + { + cpu->pc = cpu->reg[operandA]; + } case HLT: running = 0; //set running to false break; diff --git a/ls8/cpu.h b/ls8/cpu.h index 72f0864c..594e8d1a 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -44,6 +44,8 @@ enum alu_op { #define RET 0b00010001 #define CMP 0b10100111 #define JMP 0b01010100 +#define JEQ 0b01010101 +#define JNE 0b01010110 // Function declarations From bc63427073561c749839a5cd42bf3a3a7b065863 Mon Sep 17 00:00:00 2001 From: IAN CAMERON Date: Fri, 8 Mar 2019 11:07:45 -0700 Subject: [PATCH 21/21] adds jne --- ls8/cpu.c | 8 +++++ ls8/examples/tests.ls8 | 79 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 ls8/examples/tests.ls8 diff --git a/ls8/cpu.c b/ls8/cpu.c index 41c1e6f8..15df25da 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -219,6 +219,14 @@ void cpu_run(struct cpu *cpu) { cpu->pc = cpu->reg[operandA]; } + break; + case JNE: + //if equal flag is clear/false/0 jump to address stored at given register. + if ((cpu->fl & 0b00000001) == 0) + { + cpu->pc = cpu->reg[operandA]; + } + break; case HLT: running = 0; //set running to false break; diff --git a/ls8/examples/tests.ls8 b/ls8/examples/tests.ls8 new file mode 100644 index 00000000..720390cb --- /dev/null +++ b/ls8/examples/tests.ls8 @@ -0,0 +1,79 @@ +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 \ No newline at end of file