-
Notifications
You must be signed in to change notification settings - Fork 6
init commit Comp architect Toua #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
097125f
6fb34ac
0514689
57b464c
bcd0518
ac04506
bb80a55
b6b9e54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,58 +1,156 @@ | ||
| #include "cpu.h" | ||
| #include <stdio.h> | ||
| #include <string.h> | ||
| #include <stdlib.h> | ||
|
|
||
| /** | ||
| * Load the binary bytes from a .ls8 source file into a RAM array | ||
| */ | ||
| void cpu_load(struct cpu *cpu) | ||
|
|
||
| #define DATA_LEN 6 | ||
| #define SP 7 | ||
|
|
||
| unsigned char cpu_ram_read(struct cpu *cpu, unsigned mar) | ||
| { | ||
| return cpu->ram[mar]; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| void cpu_ram_write(struct cpu *cpu, unsigned char mar, unsigned char mdr) | ||
| { | ||
| cpu->ram[mar] = mdr; | ||
| } | ||
|
|
||
| void push(struct cpu *cpu, unsigned char value) | ||
| { | ||
| const int DATA_LEN = 6; | ||
| char data[DATA_LEN] = { | ||
| // From print8.ls8 | ||
| 0b10000010, // LDI R0,8 | ||
| 0b00000000, | ||
| 0b00001000, | ||
| 0b01000111, // PRN R0 | ||
| 0b00000000, | ||
| 0b00000001 // HLT | ||
| }; | ||
| cpu->registers[SP]--; | ||
| cpu_ram_write(cpu, cpu->registers[SP], value); | ||
| } | ||
|
|
||
| unsigned char pop(struct cpu *cpu) | ||
| { | ||
| unsigned char value = cpu_ram_read(cpu, cpu->registers[SP]); | ||
|
|
||
| cpu->registers[SP]++; | ||
| return value; | ||
| } | ||
|
|
||
|
|
||
| void cpu_load(struct cpu *cpu, char *filename) | ||
| { | ||
|
|
||
|
|
||
| FILE *fp = fopen(filename, "r"); | ||
|
|
||
| if(fp == NULL) { | ||
| fprintf(stderr, "ls8: error opening file: %s\n", filename); | ||
| exit(1); | ||
| } | ||
|
|
||
| char buff[8192]; | ||
| int address = 0; | ||
|
|
||
| for (int i = 0; i < DATA_LEN; i++) { | ||
| cpu->ram[address++] = data[i]; | ||
| while (fgets(buff, sizeof buff, fp) != NULL) { | ||
| unsigned char val = strtoul(buff, NULL, 2); | ||
| cpu_ram_write(cpu, address++, val); | ||
| } | ||
|
|
||
|
|
||
| fclose(fp); | ||
|
|
||
| } | ||
|
|
||
|
|
||
|
|
||
| // TODO: Replace this with something less hard-coded | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * ALU | ||
| */ | ||
| void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB) | ||
| { | ||
|
|
||
| unsigned char num_A = cpu->registers[regA]; | ||
| unsigned char num_B = cpu->registers[regB]; | ||
|
|
||
| switch (op) { | ||
| case ALU_MUL: | ||
| // TODO | ||
| cpu->registers[regA] = num_A * num_B; | ||
| break; | ||
| case ALU_ADD: | ||
| cpu->registers[regA] = num_A + num_B; | ||
| break; | ||
|
|
||
| // TODO: implement more ALU ops | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| /** | ||
| * Run the CPU | ||
| */ | ||
| void cpu_run(struct cpu *cpu) | ||
| { | ||
| int running = 1; // True until we get a HLT instruction | ||
| unsigned char IR, operandA, operandB; | ||
|
|
||
|
|
||
| while (running) { | ||
| // TODO | ||
| // 1. Get the value of the current instruction (in address PC). | ||
| IR = cpu_ram_read(cpu, cpu->PC); | ||
| operandA = cpu_ram_read(cpu, cpu->PC+1); | ||
| operandB = cpu_ram_read(cpu, cpu->PC+2); | ||
|
|
||
|
|
||
| // 2. switch() over it to decide on a course of action. | ||
| switch (IR) { | ||
| case LDI: | ||
| cpu->registers[operandA] = operandB; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good! |
||
| cpu->PC += 3; | ||
| break; | ||
| case MUL: | ||
| alu(cpu, ALU_MUL, operandA, operandB); | ||
| cpu->PC += 3; | ||
| break; | ||
| case ADD: | ||
| alu(cpu, ALU_ADD, operandA, operandB); | ||
| cpu->PC += 3; | ||
| case POP: | ||
| cpu->registers[operandA] = pop(cpu); | ||
| cpu->PC += 2; | ||
| break; | ||
| case PRN: | ||
| printf("%d\n", cpu->registers[operandA]); | ||
| cpu->PC += 2; | ||
| break; | ||
| case PUSH: | ||
| push(cpu, cpu->registers[operandA]); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just out of curiosity, why did you make the functionality of push and pop in helper functions instead of just putting that in this switch? |
||
| cpu->PC += 2; | ||
| break; | ||
| case CALL: | ||
| push(cpu, (cpu->PC + 2)); | ||
| cpu->PC = cpu->registers[operandA]; | ||
| break; | ||
| case RET: | ||
| cpu->PC = pop(cpu); | ||
| break; | ||
| case HTL: | ||
| running = 0; | ||
| cpu->PC += 1; | ||
| break; | ||
| default: | ||
| printf("Unexpected instruction 0x%02X at 0x%02X\n", IR, cpu->PC); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great tool for debugging. |
||
| exit(1); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| // 3. Do whatever the instruction should do according to the spec. | ||
| // 4. Move the PC to the next instruction. | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -61,6 +159,14 @@ void cpu_run(struct cpu *cpu) | |
| void cpu_init(struct cpu *cpu) | ||
| { | ||
| // TODO: Initialize the PC and other special registers | ||
|
|
||
| for (int i = 0; i < 6; i++) | ||
| { | ||
| cpu->registers[i] = 0; | ||
| } | ||
| cpu->PC = 0; | ||
| cpu->FL = 0; | ||
| cpu->registers[7] = 0xF4; | ||
| // TODO: Zero registers and RAM | ||
| memset(cpu->ram, 0, sizeof(cpu->ram)); | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,8 +5,18 @@ | |
| struct cpu { | ||
| // TODO | ||
| // PC | ||
| unsigned char PC; | ||
| unsigned char FL; | ||
| // registers (array) | ||
| unsigned char registers[8]; | ||
| // ram (array) | ||
| unsigned char ram[256]; | ||
| }; | ||
|
|
||
| enum alu_op { | ||
| ALU_MUL, | ||
| ALU_ADD | ||
|
|
||
| }; | ||
|
|
||
| // Instructions | ||
|
|
@@ -15,11 +25,19 @@ struct cpu { | |
| // literals should be used. | ||
|
|
||
| #define LDI 0b10000010 | ||
| #define PRN 0b01000111 | ||
| #define HTL 0b00000001 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be |
||
| #define MUL 0b10100010 | ||
| #define PUSH 0b01000101 | ||
| #define POP 0b01000110 | ||
| #define ADD 0b10100000 | ||
|
|
||
|
|
||
| // 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); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good. Well done with using
cpu_ram_write()instead of just assigning the value.