diff --git a/.vscode/ipch/d84610e55772ae16/mmap_address.bin b/.vscode/ipch/d84610e55772ae16/mmap_address.bin new file mode 100644 index 00000000..862b8428 Binary files /dev/null and b/.vscode/ipch/d84610e55772ae16/mmap_address.bin differ diff --git a/.vscode/ipch/d84617e55772b9fb/cpu.ipch b/.vscode/ipch/d84617e55772b9fb/cpu.ipch new file mode 100644 index 00000000..2aa5e66d Binary files /dev/null and b/.vscode/ipch/d84617e55772b9fb/cpu.ipch differ diff --git a/.vscode/ipch/d84617e55772b9fb/mmap_address.bin b/.vscode/ipch/d84617e55772b9fb/mmap_address.bin new file mode 100644 index 00000000..862b8428 Binary files /dev/null and b/.vscode/ipch/d84617e55772b9fb/mmap_address.bin differ diff --git a/.vscode/ipch/e56e8d2c582b3ea6/ls8.ipch b/.vscode/ipch/e56e8d2c582b3ea6/ls8.ipch new file mode 100644 index 00000000..64277151 Binary files /dev/null and b/.vscode/ipch/e56e8d2c582b3ea6/ls8.ipch differ diff --git a/.vscode/ipch/e56e8d2c582b3ea6/mmap_address.bin b/.vscode/ipch/e56e8d2c582b3ea6/mmap_address.bin new file mode 100644 index 00000000..862b8428 Binary files /dev/null and b/.vscode/ipch/e56e8d2c582b3ea6/mmap_address.bin differ diff --git a/ls8/cpu.c b/ls8/cpu.c index bdb1f506..d34968e7 100644 --- a/ls8/cpu.c +++ b/ls8/cpu.c @@ -1,31 +1,70 @@ #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, int argc, char *argv[]) { - 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]; + + if (argc < 2) + { + printf("File does not exist.\n"); + exit(1); + } + + char *file = argv[1]; + + + FILE *fp = fopen(file, "r"); + + + if (fp == NULL) + { + printf("File does not exist"); + exit(1); + } + else + { + char file_line[1024]; + int address = 0; + + while (fgets(file_line, sizeof(file_line), fp) != NULL) + { + + char *endptr; + unsigned char val = strtol(file_line, &endptr, 2); + + + if (file_line == NULL) + { + continue; + } + + cpu->ram[address] = val; + address++; + } } - // TODO: Replace this with something less hard-coded + fclose(fp); +} + +unsigned char cpu_ram_read(struct cpu *cpu, unsigned char index ) +{ + return cpu->ram[index]; +} + +unsigned char cpu_ram_write(struct cpu *cpu, int index, unsigned char value) +{ + return cpu->ram[index] = value; } + + /** * ALU */ @@ -33,28 +72,138 @@ void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB { switch (op) { case ALU_MUL: - // TODO + cpu->registers[regA] = cpu->registers[regA] * cpu->registers[regB]; break; - // TODO: implement more ALU ops + case ALU_ADD: + cpu->registers[regA] = cpu->registers[regA] + cpu->registers[regB]; + break; + + case ALU_CMP: + if(cpu->registers[regA] == cpu->registers[regB]) + { + cpu->FL = 1; + } + else if(cpu->registers[regA] > cpu->registers[regB]) + { + cpu->FL = 0; + } + + break; } } +void push_stack(struct cpu *cpu, int val) +{ + cpu->registers[7]--; + cpu_ram_write(cpu, cpu->registers[7], val); +} + +unsigned char pop_stack(struct cpu *cpu) +{ + unsigned char val = cpu->ram[cpu->registers[7]]; + cpu->registers[7]++; + return val; +} + /** * Run the CPU */ void cpu_run(struct cpu *cpu) { int running = 1; // True until we get a HLT instruction + unsigned char operandA; + unsigned char operandB; + while (running) { // TODO // 1. Get the value of the current instruction (in address PC). + unsigned char IR = cpu->ram[cpu->PC]; // 2. Figure out how many operands this next instruction requires + unsigned int num_operands = IR >> 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); + } + + // printf("%d\n", IR); + // 4. switch() over it to decide on a course of action. + switch (IR) + { + case HLT: + running = 0; + break; + + case LDI: + cpu->registers[operandA] = operandB; + break; + + case PRN: + printf("%d\n", cpu->registers[operandA]); + break; + + case MUL: + alu(cpu, ALU_MUL, operandA, operandB); + break; + + case PUSH: + push_stack(cpu, cpu->registers[operandA]); + break; + + case POP: + cpu->registers[operandA] = pop_stack(cpu); + break; + + case CALL: + push_stack(cpu, cpu->PC + 1); + cpu->PC = cpu->registers[operandA] - 1; + break; + + case RET: + cpu->PC = pop_stack(cpu); + break; + + case ADD: + alu(cpu, ALU_ADD, operandA, operandB); + break; + + case CMP: + alu(cpu, ALU_CMP, operandA, operandB); + break; + + case JMP: + cpu->PC = cpu->registers[operandA]; + cpu->PC += 1; + break; + + case JEQ: + if (cpu->FL == 1) + { + cpu->PC = cpu->registers[operandA]; + } + break; + + case JNE: + if (cpu->FL != 1) + { + cpu->PC = cpu->registers[operandA]; + } + 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; } } @@ -63,5 +212,12 @@ void cpu_run(struct cpu *cpu) */ void cpu_init(struct cpu *cpu) { - // TODO: Initialize the PC and other special registers + cpu->PC = 0; + cpu->FL = 0; + memset(cpu->ram, 0, sizeof(cpu->ram)); + memset(cpu->registers, 0, sizeof(cpu->registers)); + + int total = sizeof(cpu->ram) / sizeof(unsigned char); + cpu->registers[7] = total; } + diff --git a/ls8/cpu.h b/ls8/cpu.h index 46e49c44..60ceaeec 100644 --- a/ls8/cpu.h +++ b/ls8/cpu.h @@ -5,14 +5,20 @@ struct cpu { // TODO // PC + unsigned int PC; // registers (array) + unsigned char registers[8]; // ram (array) + unsigned char ram[256]; + //flag + unsigned char FL; }; // ALU operations enum alu_op { - ALU_MUL - // Add more here + ALU_MUL, + ALU_ADD, + ALU_CMP }; // Instructions @@ -24,10 +30,20 @@ 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 +#define ADD 0b10100000 +#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); diff --git a/ls8/examples/sctest.ls8 b/ls8/examples/sctest.ls8 new file mode 100644 index 00000000..720390cb --- /dev/null +++ b/ls8/examples/sctest.ls8 @@ -0,0 +1,79 @@ +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 \ No newline at end of file diff --git a/ls8/ls8.c b/ls8/ls8.c index d24578ee..18cc29e4 100644 --- a/ls8/ls8.c +++ b/ls8/ls8.c @@ -4,12 +4,12 @@ /** * 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;