Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Binary file added .vscode/ipch/2a75f9e806ad4e89/LS8.ipch
Binary file not shown.
Binary file added .vscode/ipch/2a75f9e806ad4e89/mmap_address.bin
Binary file not shown.
Binary file added .vscode/ipch/a8e8d6eb045d52d8/CPU.ipch
Binary file not shown.
Binary file added .vscode/ipch/a8e8d6eb045d52d8/mmap_address.bin
Binary file not shown.
227 changes: 203 additions & 24 deletions ls8/cpu.c
Original file line number Diff line number Diff line change
@@ -1,42 +1,124 @@
#include "cpu.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//really do hope I did this correctly
#define DATA_LEN 6
// stack pointer
#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, int argc, char *argv[]) // make ./ls8 examples/print8.ls8
{
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];
// TODO: Replace this with something less hard-coded

// if argc is < 2, "File does not exist"
if (argc < 2)
{
printf("File does not exist.\n");
exit(1);
}

// TODO: Replace this with something less hard-coded
char *file = argv[1];

// need file
FILE *fp = fopen(file, "r");

// if file does not exist
if (fp == NULL)
{
printf("File does not exist");
exit(1);
}
else
{
// create a var that will hold line of file
char file_line[1024];
int address = 0;

// while not end of file
while (fgets(file_line, sizeof(file_line), fp) != NULL)
{
// cycle through ram and store value of line into ram
char *ptr;
unsigned char return_value;
return_value = strtol(file_line, &ptr, 2);

// if empty line continue
if (file_line == NULL)
{
continue;
}

cpu->ram[address] = return_value;
address++;
}
}
// close file
fclose(fp);
}

// cpu read ram
// would have to take a cpu struct and an index for ram
unsigned char cpu_ram_read(struct cpu *cpu, unsigned char memadr)
{
return cpu->ram[memadr];
}

// cpu write ram
// would have to take a cpu struct, an index for ram, and char value
void cpu_ram_write(struct cpu *cpu, unsigned char memadr, unsigned char value)
{
cpu->ram[memadr] = value;
}

// cpu push
void cpu_push(struct cpu *cpu, unsigned char value)
{
// decrement stack pointer
cpu->reg[SP]--;
cpu_ram_write(cpu, cpu->reg[SP], value);
}

// cpu pop
unsigned char cpu_pop(struct cpu *cpu)
{
unsigned char ret = cpu->ram[cpu->reg[SP]];
cpu->reg[SP]++;
return ret;
}

//

/**
* ALU
*/
void alu(struct cpu *cpu, enum alu_op op, unsigned char regA, unsigned char regB)
{
switch (op) {
case ALU_MUL:
// TODO
break;
switch (op)
{
case ALU_MUL:
// TODO
cpu->reg[regA] *= cpu->reg[regB];
break;

// TODO: implement more ALU ops
// TODO: implement more ALU ops
case ALU_ADD:
cpu->reg[regA] += cpu->reg[regB];
break;

case ALU_CMP:
if (cpu->reg[regA] == cpu->reg[regB])
{
cpu->FL = 1;
}
else if (cpu->reg[regA] > cpu->reg[regB])
{
cpu->FL = 0;
}
break;
}
}

Expand All @@ -46,15 +128,104 @@ 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
// create ops
unsigned char operandA;
unsigned char operandB;

while (running) {
while (running)
{
// TODO

// 1. Get the value of the current instruction (in address PC).
unsigned char instruction = cpu->ram[cpu->PC];

// 2. Figure out how many operands this next instruction requires
unsigned int num_operands = instruction >> 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);
}

// 4. switch() over it to decide on a course of action.
switch (instruction)
{
case HLT:
running = 0;
break;

case PRN:
// print whatever is in the specified register
printf("%d\n", cpu->reg[operandA]);
break;

case LDI:
cpu->reg[operandA] = operandB;
break;

case MUL:
alu(cpu, ALU_MUL, operandA, operandB);
break;

// uses function cpu_push that pushes value into reg
case PUSH:
cpu_push(cpu, cpu->reg[operandA]);
break;

case POP:
cpu->reg[operandA] = cpu_pop(cpu);
break;

case ADD:
alu(cpu, ALU_ADD, operandA, operandB);
break;

case CALL:
cpu_push(cpu, cpu->PC + 1);
cpu->PC = cpu->reg[operandA] - 1;
break;

case RET:
cpu->PC = cpu_pop(cpu);
break;

case CMP:
alu(cpu, ALU_CMP, operandA, operandB);
break;

case JMP:
cpu->PC = cpu->reg[operandA];
cpu->PC += 1;
break;

case JEQ:
if (cpu->FL == 1)
{
cpu->PC = cpu->reg[operandA];
cpu->PC -= 1;
}
break;

case JNE:
if (cpu->FL != 1)
{
cpu->PC = cpu->reg[operandA];
cpu->PC -= 1;
}
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;
}
}

Expand All @@ -64,4 +235,12 @@ void cpu_run(struct cpu *cpu)
void cpu_init(struct cpu *cpu)
{
// TODO: Initialize the PC and other special registers
}
// set all values to 0
cpu->PC = 0;
cpu->FL = 0;

cpu->reg[SP] = ADDR_EMPTY_STACK;

memset(cpu->reg, 0, sizeof(cpu->reg));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great job figuring out and applying memset here

memset(cpu->ram, 0, sizeof(cpu->ram));
}
43 changes: 34 additions & 9 deletions ls8/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,58 @@
#define _CPU_H_

// Holds all information about the CPU
struct cpu {
struct cpu
{
// TODO
// PC
unsigned int PC;
// stack pointer
unsigned int SP;
// flag
unsigned char FL;
// registers (array)
// 8 for 0-7
unsigned char reg[8];
// ram (array)
unsigned char ram[256];
};

#define ADDR_PROGRAM_ENTRY 0x00 // program gets loaded
#define ADDR_EMPTY_STACK 0xF4 // sp is empty

// ALU operations
enum alu_op {
ALU_MUL
// Add more here
enum alu_op
{
ALU_MUL,
// Add more here
ALU_ADD,
ALU_CMP
};

// Instructions

// These use binary literals. If these aren't available with your compiler, hex
// literals should be used.

#define LDI 0b10000010
#define HLT 0b00000001
#define PRN 0b01000111
#define LDI 0b10000010
#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 ADD 0b10100000
#define CALL 0b01010000
#define RET 0b00010001
#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);

#endif
#endif
5 changes: 3 additions & 2 deletions ls8/ls8.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@

#include <stdio.h>
#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, argc, argv);
cpu_run(&cpu);

return 0;
Expand Down