From b5599ae5509a013108f803837d1e639a6b4488bc Mon Sep 17 00:00:00 2001 From: Vuk Radosavljevic Date: Wed, 27 Feb 2019 15:39:51 -0600 Subject: [PATCH 1/3] Finished HLT, LDI, and PRN operands --- ls8/cpu.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ ls8/cpu.h | 5 ++++- ls8/ls8.c | 2 +- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..bf7a4f95 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,10 +1,26 @@ #include "cpu.h" +#include +#include +#include #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 */ + void cpu_load(struct cpu *cpu) { char data[DATA_LEN] = { @@ -48,11 +64,34 @@ 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). + unsigned char ir = cpu_ram_read(cpu, cpu->pc); // 2. Figure out how many operands this next instruction requires + unsigned char operandA = cpu_ram_read(cpu, cpu->pc+1); + unsigned char operandB = cpu_ram_read(cpu, cpu->pc+2); // 3. Get the appropriate value(s) of the operands following this instruction // 4. switch() over it to decide on a course of action. + switch(ir) { + + case LDI: + cpu->registers[operandA] = operandB; + cpu->pc += 3; + break; + case HLT: + running = 0; + break; + case PRN: + printf("%d\n", cpu->registers[operandA]); + cpu->pc += 2; + break; + default: + running = 0; + break; + } + + // 5. Do whatever the instruction should do according to the spec. // 6. Move the PC to the next instruction. } @@ -63,5 +102,11 @@ void cpu_run(struct cpu *cpu) */ void cpu_init(struct cpu *cpu) { + cpu->pc = 0; + memset(cpu->ram, 0, sizeof(cpu->ram)); + memset(cpu->registers, 0, sizeof(cpu->registers)); // TODO: Initialize the PC and other special registers + ///Initalize our cpu, start ram and registers and pc to 0 memset() might help } + + diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..72ecf8a8 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -4,9 +4,12 @@ // Holds all information about the CPU struct cpu { // TODO - // PC + // PC - keeps the index of the currently executing instruction + unsigned char pc; // registers (array) + unsigned char registers[8]; // ram (array) + unsigned char ram[256]; }; // ALU operations diff --git a/ls8/ls8.c b/ls8/ls8.c index d24578ee..6809928a 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -13,4 +13,4 @@ int main(void) cpu_run(&cpu); return 0; -} \ No newline at end of file +} From 9a84a9ee2bccc1271efe6dde389710bd4fcdc6f7 Mon Sep 17 00:00:00 2001 From: Vuk Radosavljevic Date: Fri, 1 Mar 2019 11:43:03 -0600 Subject: [PATCH 2/3] Added CMP, JMP, JEQ --- ls8/cpu.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++-------- ls8/cpu.h | 16 +++++++- ls8/ls8.c | 16 +++++++- 3 files changed, 119 insertions(+), 20 deletions(-) diff --git a/ls8/cpu.c b/ls8/cpu.c index bf7a4f95..99889029 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -21,25 +21,52 @@ 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 *filename) { - char data[DATA_LEN] = { - // From print8.ls8 - 0b10000010, // LDI R0,8 - 0b00000000, - 0b00001000, - 0b01000111, // PRN R0 - 0b00000000, - 0b00000001 // HLT - }; + // 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]; + // } - int address = 0; + // TODO: Replace this with something less hard-coded + FILE *fp = fopen(filename, "r"); - for (int i = 0; i < DATA_LEN; i++) { - cpu->ram[address++] = data[i]; + if (fp == NULL) { + fprintf(stderr, "error opening file"); + exit(2); } - // TODO: Replace this with something less hard-coded + char line[8192]; + int address = 0; + + + while (fgets(line, sizeof line, fp) != NULL) { + + char *endptr; + unsigned char val = strtoul(line, &endptr, 2); + + if (endptr == NULL) { + continue; + } + + + cpu->ram[address++] = val; + } + + fclose(fp); + + } /** @@ -47,12 +74,22 @@ void cpu_load(struct cpu *cpu) */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { + + unsigned char firstValue = cpu->reg[regA]; + unsigned char secondValue = cpu->reg[regB]; switch (op) { case ALU_MUL: // TODO + cpu->reg[regA] = firstValue * secondValue; + break; + case ALU_ADD: + cpu->reg[regA] = firstValue + secondValue; break; - // TODO: implement more ALU ops + case CMP: + if (firstValue == secondValue) { + cpu->FL = 0; + } } } @@ -86,9 +123,45 @@ 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; + //Jumps to the address stored in the given register + case CMP: + alu(cpu, operandA, operandB); + cpu->pc += 3; + break; + case JMP: + cpu->pc = cpu->registers[operandA]; + cpu->pc += 2; + break; + ///IF equal flag is set to true jump to the address in the register + case JEQ: + if (cpu->FL == 1) { + cpu->pc = cpu->registers[operandA]; + cpu->FL = 0; + } else { + cpu->pc += 2; + cpu->FL = 0; + } + break; + case JNE: + if ((cpu->FL & 1) != 1) { + cpu->pc = cpu->registers[operandA]; + cpu->FL = 0; + } else { + cpu->pc += 2; + cpu->FL = 0; + } + break; default: running = 0; - break; + // break; } @@ -103,8 +176,10 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { cpu->pc = 0; + cpu->FL = 0b00000000; memset(cpu->ram, 0, sizeof(cpu->ram)); memset(cpu->registers, 0, sizeof(cpu->registers)); + cpu->registers[7] = 0xF4; // TODO: Initialize the PC and other special registers ///Initalize our cpu, start ram and registers and pc to 0 memset() might help } diff --git a/ls8/cpu.h b/ls8/cpu.h index 72ecf8a8..07ed8447 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -4,6 +4,8 @@ // Holds all information about the CPU struct cpu { // TODO + //Flag + int FL; // PC - keeps the index of the currently executing instruction unsigned char pc; // registers (array) @@ -14,7 +16,9 @@ struct cpu { // ALU operations enum alu_op { - ALU_MUL + ALU_MUL, + ALU_ADD, + ALU_CMP // Add more here }; @@ -26,11 +30,19 @@ enum alu_op { #define LDI 0b10000010 #define HLT 0b00000001 #define PRN 0b01000111 +#define MUL 0b10100010 +#define ADD 0b10100000 +#define CMP 0b10100111 +#define JMP 0b01010100 +#define JEQ 0b01010101 +#define JNE 0b01010110 + + // TODO: more instructions here. These can be used in cpu_run(). // 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 6809928a..3326b5dd 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,12 +4,24 @@ /** * Main */ -int main(void) +int main(int argc, char **argv) { + + + struct cpu cpu; + + if (argc != 2) { + fprintf(stderr, "pass in a valid file only"); + return(1); + } + + //Gets the filename that was passed in from the command line + char *filename = argv[1]; + cpu_init(&cpu); - cpu_load(&cpu); + cpu_load(&cpu, filename); cpu_run(&cpu); return 0; From a1c5784c9fa821f9438c6b129999fd600d955782 Mon Sep 17 00:00:00 2001 From: Vuk Radosavljevic Date: Mon, 4 Mar 2019 10:36:19 -0600 Subject: [PATCH 3/3] Fixed typo --- asm/sctest.ls8 | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ ls8/cpu.c | 12 +++---- 2 files changed, 92 insertions(+), 6 deletions(-) create mode 100755 asm/sctest.ls8 diff --git a/asm/sctest.ls8 b/asm/sctest.ls8 new file mode 100755 index 00000000..8f86bba7 --- /dev/null +++ b/asm/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 diff --git a/ls8/cpu.c b/ls8/cpu.c index 99889029..e5394334 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -75,18 +75,18 @@ 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 firstValue = cpu->reg[regA]; - unsigned char secondValue = cpu->reg[regB]; + unsigned char firstValue = cpu->registers[regA]; + unsigned char secondValue = cpu->registers[regB]; switch (op) { case ALU_MUL: // TODO - cpu->reg[regA] = firstValue * secondValue; + cpu->registers[regA] = firstValue * secondValue; break; case ALU_ADD: - cpu->reg[regA] = firstValue + secondValue; + cpu->registers[regA] = firstValue + secondValue; break; // TODO: implement more ALU ops - case CMP: + case ALU_CMP: if (firstValue == secondValue) { cpu->FL = 0; } @@ -133,7 +133,7 @@ void cpu_run(struct cpu *cpu) break; //Jumps to the address stored in the given register case CMP: - alu(cpu, operandA, operandB); + alu(cpu, ALU_CMP, operandA, operandB); cpu->pc += 3; break; case JMP: