Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Computer Architecture
# Computer Architecture -

## Project

Expand All @@ -7,22 +7,24 @@
## Task List: add this to the first comment of your Pull Request

### Day 1: Get `print8.ls8` running
- [ ] Inventory what is here
- [ ] Implement `struct cpu` in `cpu.h`
- [ ] Add RAM functions `cpu_ram_read` and `cpu_ram_write`
- [ ] Implement `cpu_init()`
- [ ] Implement the core of `cpu_run()`
- [ ] Implement the `HLT` instruction handler
- [ ] Add the `LDI` instruction
- [ ] Add the `PRN` instruction
- [x] Inventory what is here
- [x] Implement `struct cpu` in `cpu.h`
- [x] Add RAM functions `cpu_ram_read` and `cpu_ram_write`
- [x] Implement `cpu_init()`
- [x] Implement the core of `cpu_run()`
- [x] Implement the `HLT` instruction handler
- [x] Add the `LDI` instruction
- [x] Add the `PRN` instruction

### Day 2: Add the ability to load files dynamically, get `mult.ls8` and `stack.ls8` running
- [ ] Un-hardcode the machine code
- [ ] Implement the `cpu_load` function to load an `.ls8` file given the filename passed in as an argument
- [ ] Implement a Multiply instruction and Print the result (run `mult8.ls8`)
- [x] Un-hardcode the machine code
- [x] Implement the `cpu_load` function to load an `.ls8` file given the filename passed in as an argument
- [x] Implement a Multiply instruction and Print the result (run `mult8.ls8`)

### Day 3:
- [ ] Implement the System Stack and be able to run the `stack.ls8` program

### Day 3: Get `call.ls8` running
### Day 4: Get `call.ls8` running
- [ ] Implement the CALL and RET instructions
- [ ] Implement Subroutine Calls and be able to run the `call.ls8` program

Expand Down
126 changes: 108 additions & 18 deletions ls8/cpu.c
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
#include "cpu.h"
#include "string.h"
#include "stdio.h"
#include <stdlib.h>

#define DATA_LEN 6
#define DATA_LEN 12

/**
* 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 *program)
{
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 *fp;

char line[1024];

fp = fopen(program, "r");

if( fp == NULL) {
fprintf(stderr, "Error opening file.\n");
exit(1);
}

// TODO: Replace this with something less hard-coded
int i = 0;
while( fgets(line, sizeof(line), fp) != NULL ) {
char *endPtr;
unsigned char byte = strtol(line, &endPtr, 2);

if(endPtr == line) {
continue;
}

cpu_ram_write(cpu, i, byte);
i++;
}

fclose(fp);

}

unsigned char cpu_ram_read(struct cpu *cpu, unsigned char address)
{
return cpu->ram[address];
}

void cpu_ram_write(struct cpu *cpu, int address, unsigned char value)
{
cpu->ram[address] = value;
}

/**
Expand All @@ -47,14 +70,76 @@ void cpu_run(struct cpu *cpu)
{
int running = 1; // True until we get a HLT instruction

int stack[256];
int sp = 7;

//int PC = cpu->PC;
//unsigned char value;

while (running) {
// TODO
// 1. Get the value of the current instruction (in address PC).
unsigned char instruction = cpu_ram_read(cpu, cpu->PC);
// 2. Figure out how many operands this next instruction requires
// 3. Get the appropriate value(s) of the operands following this instruction
unsigned char operandA = cpu_ram_read(cpu, cpu->PC + 1);
unsigned char operandB = cpu_ram_read(cpu, cpu->PC + 2);

// 4. switch() over it to decide on a course of action.
// 5. Do whatever the instruction should do according to the spec.
// 6. Move the PC to the next instruction.
switch(instruction) {

case HLT:
running = 0;
break;

case LDI:
cpu->registers[operandA] = operandB;
cpu->PC += 3;
break;

case PRN:
printf("%d\n", cpu->registers[operandA]);
cpu->PC += 2;
break;

case MUL:
cpu->registers[operandA] = (cpu->registers[operandA] * cpu->registers[operandB]);
//test that MUL completed successfully
printf("%d\n", cpu->registers[operandA]);
cpu->PC += 2;
break;

case PUSH:
sp--;
stack[sp] = cpu->registers[operandA];
cpu->PC += 2;
break;

case POP:
cpu->registers[operandA] = stack[sp];
sp++;
cpu->PC += 2;
break;

case CALL:
sp--;
stack[sp] = cpu->registers[operandA];
cpu->PC = cpu->registers[operandA];

cpu_ram_read(cpu, cpu->PC);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be writing to RAM instead:
cpu_ram_write(cpu, stack[sp], cpu->pc+2);
But the way you setup your stack will conlfict with this. It may be easier for you to just create push and pop functions to increment and derement the stack pointer and then write the value you want to push to ram at the stack pointer.
Something like this:
push (struct *cpu, unsigned char val): { cpu->registers[sp] --; cpu_ram_write(cpu, val, cpu->reg[sp]); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So with what you're doing I think you're just reading from RAM at the program count, and never even referencing the stack.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure how you can call the right instruction this way.

break;

case RET:
cpu->registers[operandA] = stack[sp];
sp++;

cpu->PC = cpu->registers[operandA];
break;


}
}
}

Expand All @@ -63,5 +148,10 @@ void cpu_run(struct cpu *cpu)
*/
void cpu_init(struct cpu *cpu)
{
// TODO: Initialize the PC and other special registers
cpu->PC = 0;

memset(cpu->registers, 0, 8*sizeof(unsigned char));

memset(cpu->ram, 0, 8*sizeof(unsigned char));

}
10 changes: 9 additions & 1 deletion ls8/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
struct cpu {
// TODO
// PC
int PC;
// registers (array)
unsigned char registers[8];
// ram (array)
unsigned char ram[8];
};

// ALU operations
Expand All @@ -23,11 +26,16 @@ enum alu_op {
#define LDI 0b10000010
#define HLT 0b00000001
#define PRN 0b01000111
#define MUL 0b10100010
#define PUSH 0b01000101
#define POP 0b01000110
#define CALL 0b01010000
#define RET 0b00010001
// 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 *program);
extern void cpu_init(struct cpu *cpu);
extern void cpu_run(struct cpu *cpu);

Expand Down
20 changes: 16 additions & 4 deletions ls8/ls8.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
#include <stdio.h>
#include "cpu.h"
#include <stdlib.h>

/**
* Main
*/
int main(void)
int main(int argc, char **argv)
{
struct cpu cpu;
char *program;

cpu_init(&cpu);
cpu_load(&cpu);
cpu_run(&cpu);
if (argc < 2) {
fprintf(stderr, "Please specify which program the LS8 should run.\nUsage: ls8 program\n");
exit(1);

} else {
program = argv[1];

printf("%s\n", program);

cpu_init(&cpu);
cpu_load(&cpu, program);
cpu_run(&cpu);
}

return 0;
}