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 bdb1f506..e5394334 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,29 +1,72 @@ #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) + +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; + // int address = 0; - for (int i = 0; i < DATA_LEN; i++) { - cpu->ram[address++] = data[i]; - } + // for (int i = 0; i < DATA_LEN; i++) { + // cpu->ram[address++] = data[i]; + // } // TODO: Replace this with something less hard-coded + FILE *fp = fopen(filename, "r"); + + if (fp == NULL) { + fprintf(stderr, "error opening file"); + exit(2); + } + + 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); + + } /** @@ -31,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->registers[regA]; + unsigned char secondValue = cpu->registers[regB]; switch (op) { case ALU_MUL: // TODO + cpu->registers[regA] = firstValue * secondValue; + break; + case ALU_ADD: + cpu->registers[regA] = firstValue + secondValue; break; - // TODO: implement more ALU ops + case ALU_CMP: + if (firstValue == secondValue) { + cpu->FL = 0; + } } } @@ -48,11 +101,70 @@ 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; + 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, ALU_CMP, 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; + } + + // 5. Do whatever the instruction should do according to the spec. // 6. Move the PC to the next instruction. } @@ -63,5 +175,13 @@ 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 46e49c44..07ed8447 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -4,14 +4,21 @@ // Holds all information about the CPU struct cpu { // TODO - // PC + //Flag + int FL; + // 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 enum alu_op { - ALU_MUL + ALU_MUL, + ALU_ADD, + ALU_CMP // Add more here }; @@ -23,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 d24578ee..3326b5dd 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,13 +4,25 @@ /** * 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; -} \ No newline at end of file +}