diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..849ea206 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,29 +1,72 @@ +#include +#include +#include #include "cpu.h" #define DATA_LEN 6 +#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, char *dir) { - 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]; + FILE *fptr; + + if ((fptr = fopen(dir,"r"))== NULL) + { + fprintf(stderr, "File does not exist: %s\n",dir); + exit(1); + } + // + char temp[256]; + char *instruction; + + unsigned int counter = 0; + + while(fgets(temp,sizeof(temp),fptr) != NULL){ + instruction = strndup(temp,8); + + if (instruction[0] == '0' || instruction[0] == '1'){ + cpu->ram[counter] = strtoul(instruction,NULL,2); + counter++; + } } - // TODO: Replace this with something less hard-coded + fclose(fptr); + +} + +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address){ + return cpu->ram[address]; +} + +void cpu_ram_write(struct cpu *cpu, unsigned char value, unsigned char address){ + cpu->ram[address] = value; +} + +// Stack + +void cpu_push(struct cpu *cpu, unsigned char value) +{ + cpu->registers[SP]--; + cpu_ram_write(cpu,value, cpu->registers[SP]); + printf("PUSH :%d @ %d\n VALUE: %d\n",cpu_ram_read(cpu,cpu->registers[SP]), cpu->registers[SP], value ); +} + +unsigned char cpu_pop(struct cpu *cpu){ + if(cpu->registers[SP] == 0xF4){ + fprintf(stderr, "stack is empty"); + exit(1); + } + + unsigned char value = cpu_ram_read(cpu,cpu->registers[SP]); + printf("POP :%d @ %d\n",value, cpu->registers[SP] ); + cpu_ram_write(cpu,cpu->registers[SP],0); + cpu->registers[SP]++; + + return value; + } /** @@ -31,12 +74,13 @@ void cpu_load(struct cpu *cpu) */ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) { + switch (op) { case ALU_MUL: // TODO - break; - + cpu->registers[regA] *= cpu->registers[regB]; // TODO: implement more ALU ops + } } @@ -46,15 +90,59 @@ 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 + // Remember Zero is interpreted as false and anything non-zero is interpreted as true. + + unsigned char IR; + unsigned char opA; + unsigned char opB; while (running) { // TODO // 1. Get the value of the current instruction (in address PC). + IR = cpu_ram_read(cpu, cpu->PC); // 2. Figure out how many operands this next instruction requires + int operands = IR >> 6; // 3. Get the appropriate value(s) of the operands following this instruction - // 4. switch() over it to decide on a course of action. + switch (operands){ + case 1: + opA = cpu_ram_read(cpu,cpu->PC+1); + case 2: + opA = cpu_ram_read(cpu,cpu->PC+1); + opB = cpu_ram_read(cpu,cpu->PC+2); + } + + // DEBUG + printf("TRACE: %02X: %02X %02X %02X %02X\n", cpu->PC, IR, opA, opB, cpu->registers[0]); + + // 4. switch() over it (THE INSTRUCTION) to decide on a course of action. + switch(IR){ // 5. Do whatever the instruction should do according to the spec. + case LDI: + // cpu_ram_write(cpu, opA, opB); + // cpu_ram_write(cpu, opB, opA); + cpu->registers[opA] = opB; + break; + case PRN: + printf("%d\n", cpu->registers[opA]); + break; + case MUL: + alu(cpu,ALU_MUL,opA,opB); + break; + case HLT: + running = 0; + break; + case PUSH: + cpu_push(cpu,cpu->registers[opA]); + break; + case POP: + cpu->registers[opA] = cpu_pop(cpu); + break; + default: + fprintf(stderr, "PC %02x: unknown instruction %02x\n", cpu->PC, IR); + exit(3); + } // 6. Move the PC to the next instruction. + cpu->PC = cpu->PC + operands + 1; } } @@ -63,5 +151,13 @@ void cpu_run(struct cpu *cpu) */ void cpu_init(struct cpu *cpu) { - // TODO: Initialize the PC and other special registers + // Initialize the PC and other special registers + + cpu->PC = 0; + cpu->FL = 0; + memset(cpu->registers,0,8); + memset(cpu->ram,0,256); + } + + diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..2833bf32 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -5,8 +5,13 @@ struct cpu { // TODO // PC + unsigned int PC; // registers (array) + unsigned char registers[8]; // ram (array) + unsigned char ram[256]; + // FL + unsigned int FL; }; // ALU operations @@ -23,11 +28,14 @@ enum alu_op { #define LDI 0b10000010 #define HLT 0b00000001 #define PRN 0b01000111 +#define MUL 0b10100010 +#define PUSH 0b01000101 +#define POP 0b01000110 // 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 *dir); extern void cpu_init(struct cpu *cpu); extern void cpu_run(struct cpu *cpu); diff --git a/ls8/examples/ls8 b/ls8/examples/ls8 new file mode 100755 index 00000000..2776f1e7 Binary files /dev/null and b/ls8/examples/ls8 differ diff --git a/ls8/ls8.c b/ls8/ls8.c index d24578ee..3a9fe969 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,12 +4,17 @@ /** * Main */ -int main(void) +int main(int argc, char *argv[]) { + if (argc != 2){ + fprintf(stderr, "Invalid number of arguments. Add arg to ls8 file.\n"); + return 1; + } + struct cpu cpu; cpu_init(&cpu); - cpu_load(&cpu); + cpu_load(&cpu, argv[1]); cpu_run(&cpu); return 0;