diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..d47cb691 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,29 +1,41 @@ #include "cpu.h" +#include +#include +#include #define DATA_LEN 6 /** * 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 *file) { - char data[DATA_LEN] = { - // From print8.ls8 - 0b10000010, // LDI R0,8 - 0b00000000, - 0b00001000, - 0b01000111, // PRN R0 - 0b00000000, - 0b00000001 // HLT - }; - + // TODO: Replace this with something less hard-coded + FILE *file_pointer; + char line[1024]; int address = 0; - for (int i = 0; i < DATA_LEN; i++) { - cpu->ram[address++] = data[i]; + file_pointer = fopen(file, "r"); + while(fgets(line, sizeof(line), file_pointer) != NULL) { + char *term; + unsigned char value; + value = strtoul(line, &term, 2); + + if(value == HLT) { + cpu->ram[address++] = value; + break; /* only break case is when HLT instruction is received */ + } + + cpu->ram[address++] = value; } +} - // TODO: Replace this with something less hard-coded +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address) { + return cpu->ram[address]; /* reads the cpu struct's contents at this specific location in memory */ + } + +void cpu_ram_write(struct cpu *cpu, unsigned char address, unsigned char value) { + cpu->ram[address] = value; /* set new data in memory */ } /** @@ -50,11 +62,97 @@ 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); /* IR = Instruction Register */ + // 2. Figure out how many operands this next instruction requires + + /* commenting these out with CALL/RET, will enable usage without pre-loaded values) + unsigned char op0 = cpu_ram_read(cpu, cpu->PC + 1); + unsigned char op1 = cpu_ram_read(cpu, cpu->PC + 2); + */ + + unsigned char op0; + unsigned char op1; + unsigned int next; + // 3. Get the appropriate value(s) of the operands following this instruction + if(IR & 0x80) { + op0 = cpu->ram[(cpu->PC + 1) & 0xff]; + op1 = cpu->ram[(cpu->PC + 2) & 0xff]; + next = 3; + } + + else if(IR & 0x40) { + op0 = cpu->ram[(cpu->PC + 1) & 0xff]; + next = 2; + } // 4. switch() over it to decide on a course of action. + /* case pseudocode for instruction handlers: + LDI -- set cpu->registers first value to next value + HLT -- set running to 0 and break + PRN -- print current register value (same as first value in LDI) + */ // 5. Do whatever the instruction should do according to the spec. + switch(IR) { + + case LDI: + { + cpu->registers[op0] = op1; + break; + } + + case MUL: + { + cpu->registers[op0] *= cpu->registers[op1]; + break; + } + + case PRN: + { + printf("%d\n", cpu->registers[op0]); + break; + } + + case POP: + { + cpu->registers[op0] = cpu_ram_read(cpu, cpu->registers[7]); + cpu->ram[cpu->registers[7]++] = 0x00; + break; + } + + case PUSH: + { + cpu_ram_write(cpu, --cpu->registers[7], cpu->registers[op0]); + break; + } + + case CALL: + { + cpu->ram[--cpu->registers[7]] = cpu->PC + next; + cpu->PC = cpu->registers[op0]; + continue; + } + + case RET: + { + cpu->PC = cpu->ram[cpu->registers[7]++]; + continue; + } + case HLT: + { + running = 0; + break; + } + + default: + { + printf("Command 0x%02x not recognized.\n", IR); + running = 0; + break; + } + } // 6. Move the PC to the next instruction. + cpu->PC = cpu->PC + next; } } @@ -64,4 +162,9 @@ void cpu_run(struct cpu *cpu) void cpu_init(struct cpu *cpu) { // TODO: Initialize the PC and other special registers + /* need to initialize PC, registers, and ram (all elements of CPU struct) */ + + cpu->PC = 0; + memset(cpu->registers, 0, 8); + memset(cpu->ram, 0, 256); } diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..7320b730 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -1,12 +1,18 @@ #ifndef _CPU_H_ #define _CPU_H_ +/* initial commit */ + // Holds all information about the CPU struct cpu { // TODO // PC + unsigned char PC; // registers (array) + unsigned char registers[8]; /* covers R0-R7 */ // ram (array) + unsigned char *ram[256]; + unsigned char FL; /* flag for later use */ }; // ALU operations @@ -24,10 +30,14 @@ enum alu_op { #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 CALL 0b01010000 +#define RET 0b00010001 // Function declarations -extern void cpu_load(struct cpu *cpu); +extern void cpu_load(struct cpu *cpu, char *file); 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..97a3f261 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -1,16 +1,22 @@ #include +#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, argv[1]); cpu_run(&cpu); + if(argc != 2) { + fprintf(stderr, "Usage: ls8 file.ls8\n"); + return 1; + } + return 0; } \ No newline at end of file