diff --git a/.vscode/ipch/2a75f9e806ad4e89/LS8.ipch b/.vscode/ipch/2a75f9e806ad4e89/LS8.ipch new file mode 100644 index 00000000..74b72866 Binary files /dev/null and b/.vscode/ipch/2a75f9e806ad4e89/LS8.ipch differ diff --git a/.vscode/ipch/2a75f9e806ad4e89/mmap_address.bin b/.vscode/ipch/2a75f9e806ad4e89/mmap_address.bin new file mode 100644 index 00000000..862b8428 Binary files /dev/null and b/.vscode/ipch/2a75f9e806ad4e89/mmap_address.bin differ diff --git a/.vscode/ipch/a8e8d6eb045d52d8/CPU.ipch b/.vscode/ipch/a8e8d6eb045d52d8/CPU.ipch new file mode 100644 index 00000000..c3d6f7d0 Binary files /dev/null and b/.vscode/ipch/a8e8d6eb045d52d8/CPU.ipch differ diff --git a/.vscode/ipch/a8e8d6eb045d52d8/mmap_address.bin b/.vscode/ipch/a8e8d6eb045d52d8/mmap_address.bin new file mode 100644 index 00000000..862b8428 Binary files /dev/null and b/.vscode/ipch/a8e8d6eb045d52d8/mmap_address.bin differ diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..1ea706a1 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,42 +1,124 @@ #include "cpu.h" - +#include +#include +#include +//really do hope I did this correctly #define DATA_LEN 6 +// stack pointer +#define SP 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, int argc, char *argv[]) // make ./ls8 examples/print8.ls8 { - 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 + + // if argc is < 2, "File does not exist" + if (argc < 2) + { + printf("File does not exist.\n"); + exit(1); } - // TODO: Replace this with something less hard-coded + char *file = argv[1]; + + // need file + FILE *fp = fopen(file, "r"); + + // if file does not exist + if (fp == NULL) + { + printf("File does not exist"); + exit(1); + } + else + { + // create a var that will hold line of file + char file_line[1024]; + int address = 0; + + // while not end of file + while (fgets(file_line, sizeof(file_line), fp) != NULL) + { + // cycle through ram and store value of line into ram + char *ptr; + unsigned char return_value; + return_value = strtol(file_line, &ptr, 2); + + // if empty line continue + if (file_line == NULL) + { + continue; + } + + cpu->ram[address] = return_value; + address++; + } + } + // close file + fclose(fp); +} + +// cpu read ram +// would have to take a cpu struct and an index for ram +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char memadr) +{ + return cpu->ram[memadr]; } +// cpu write ram +// would have to take a cpu struct, an index for ram, and char value +void cpu_ram_write(struct cpu *cpu, unsigned char memadr, unsigned char value) +{ + cpu->ram[memadr] = value; +} + +// cpu push +void cpu_push(struct cpu *cpu, unsigned char value) +{ + // decrement stack pointer + cpu->reg[SP]--; + cpu_ram_write(cpu, cpu->reg[SP], value); +} + +// cpu pop +unsigned char cpu_pop(struct cpu *cpu) +{ + unsigned char ret = cpu->ram[cpu->reg[SP]]; + cpu->reg[SP]++; + return ret; +} + +// + /** * ALU */ 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 + cpu->reg[regA] *= cpu->reg[regB]; + break; - // TODO: implement more ALU ops + // TODO: implement more ALU ops + case ALU_ADD: + cpu->reg[regA] += cpu->reg[regB]; + break; + + case ALU_CMP: + if (cpu->reg[regA] == cpu->reg[regB]) + { + cpu->FL = 1; + } + else if (cpu->reg[regA] > cpu->reg[regB]) + { + cpu->FL = 0; + } + break; } } @@ -46,15 +128,104 @@ 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 + // create ops + unsigned char operandA; + unsigned char operandB; - while (running) { + while (running) + { // TODO + // 1. Get the value of the current instruction (in address PC). + unsigned char instruction = cpu->ram[cpu->PC]; + // 2. Figure out how many operands this next instruction requires + unsigned int num_operands = instruction >> 6; + // 3. Get the appropriate value(s) of the operands following this instruction + if (num_operands == 2) + { + operandA = cpu_ram_read(cpu, (cpu->PC + 1) & 0xff); + operandB = cpu_ram_read(cpu, (cpu->PC + 2) & 0xff); + } + else if (num_operands == 1) + { + operandA = cpu_ram_read(cpu, (cpu->PC + 1) & 0xff); + } + // 4. switch() over it to decide on a course of action. + switch (instruction) + { + case HLT: + running = 0; + break; + + case PRN: + // print whatever is in the specified register + printf("%d\n", cpu->reg[operandA]); + break; + + case LDI: + cpu->reg[operandA] = operandB; + break; + + case MUL: + alu(cpu, ALU_MUL, operandA, operandB); + break; + + // uses function cpu_push that pushes value into reg + case PUSH: + cpu_push(cpu, cpu->reg[operandA]); + break; + + case POP: + cpu->reg[operandA] = cpu_pop(cpu); + break; + + case ADD: + alu(cpu, ALU_ADD, operandA, operandB); + break; + + case CALL: + cpu_push(cpu, cpu->PC + 1); + cpu->PC = cpu->reg[operandA] - 1; + break; + + case RET: + cpu->PC = cpu_pop(cpu); + break; + + case CMP: + alu(cpu, ALU_CMP, operandA, operandB); + break; + + case JMP: + cpu->PC = cpu->reg[operandA]; + cpu->PC += 1; + break; + + case JEQ: + if (cpu->FL == 1) + { + cpu->PC = cpu->reg[operandA]; + cpu->PC -= 1; + } + break; + + case JNE: + if (cpu->FL != 1) + { + cpu->PC = cpu->reg[operandA]; + cpu->PC -= 1; + } + break; + + default: + break; + } // 5. Do whatever the instruction should do according to the spec. // 6. Move the PC to the next instruction. + cpu->PC += num_operands + 1; } } @@ -64,4 +235,12 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { // TODO: Initialize the PC and other special registers -} + // set all values to 0 + cpu->PC = 0; + cpu->FL = 0; + + cpu->reg[SP] = ADDR_EMPTY_STACK; + + memset(cpu->reg, 0, sizeof(cpu->reg)); + memset(cpu->ram, 0, sizeof(cpu->ram)); +} \ No newline at end of file diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..6a25eef1 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -2,17 +2,32 @@ #define _CPU_H_ // Holds all information about the CPU -struct cpu { +struct cpu +{ // TODO // PC + unsigned int PC; + // stack pointer + unsigned int SP; + // flag + unsigned char FL; // registers (array) + // 8 for 0-7 + unsigned char reg[8]; // ram (array) + unsigned char ram[256]; }; +#define ADDR_PROGRAM_ENTRY 0x00 // program gets loaded +#define ADDR_EMPTY_STACK 0xF4 // sp is empty + // ALU operations -enum alu_op { - ALU_MUL - // Add more here +enum alu_op +{ + ALU_MUL, + // Add more here + ALU_ADD, + ALU_CMP }; // Instructions @@ -20,15 +35,25 @@ 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(). +#define MUL 0b10100010 +#define PUSH 0b01000101 +#define POP 0b01000110 +#define ADD 0b10100000 +#define CALL 0b01010000 +#define RET 0b00010001 +#define CMP 0b10100111 +#define JMP 0b01010100 +#define JEQ 0b01010101 +#define JNE 0b01010110 // Function declarations -extern void cpu_load(struct cpu *cpu); +extern void cpu_load(struct cpu *cpu, int argc, char *argv[]); 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 d24578ee..4f1a4669 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -1,15 +1,16 @@ + #include #include "cpu.h" /** * Main */ -int main(void) +int main(int argc, char *argv[]) { struct cpu cpu; cpu_init(&cpu); - cpu_load(&cpu); + cpu_load(&cpu, argc, argv); cpu_run(&cpu); return 0;