Skip to content
Open

luis #215

Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"workbench.colorCustomizations": {
"activityBar.background": "#033615",
"titleBar.activeBackground": "#044B1D",
"titleBar.activeForeground": "#F0FEF5"
}
}
168 changes: 136 additions & 32 deletions ls8/cpu.c
Original file line number Diff line number Diff line change
@@ -1,41 +1,72 @@
#include "cpu.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define DATA_LEN 6

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

void cpu_ram_write(struct cpu *cpu, unsigned char MAR, unsigned char MDR)
{
cpu->ram[MAR] = MDR;
}

/**
* 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 *filename)
{
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];
//Init the file
FILE *fp = fopen(filename, "r");

char line[1024];

unsigned char mar = 0x00;

//Check if the file exits:
if (fp == NULL)
{
fprintf(stderr, "error opening file %s\n", filename);
exit(1);
}

// TODO: Replace this with something less hard-coded
//While there's lines in the file...
while (fgets(line, sizeof line, fp) != NULL)
{
char *endptr;
unsigned char machine_code = strtoul(line, &endptr, 2);

if (endptr == line)
{
//we got no numbers
continue;
}

//Write it into Memory
cpu_ram_write(cpu, mar++, machine_code);
}

fclose(fp);
}

/**
* 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:
cpu->reg[regA] *= cpu->reg[regB];
break;

case ALU_ADD:
cpu->reg[regA] += cpu->reg[regB];
break;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

These look good. What other operations could you add to the ALU?

// TODO: implement more ALU ops
}
}
Expand All @@ -45,16 +76,83 @@ 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

while (running) {
// TODO
// 1. Get the value of the current instruction (in address PC).
// 2. Figure out how many operands this next instruction requires
// 3. Get the appropriate value(s) of the operands following this instruction
// 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.
int running = 1;

unsigned char IR;

while (running)
{
IR = cpu_ram_read(cpu, cpu->PC);
unsigned char operandA = cpu_ram_read(cpu, (cpu->PC + 1) & 0xFF);
unsigned char operandB = cpu_ram_read(cpu, (cpu->PC + 2) & 0xFF);

int add_to_pc = (IR >> 6) + 1;
switch (IR)
{
case LDI:
cpu->reg[operandA] = operandB;
break;
case MUL:
alu(cpu, ALU_MUL, operandA, operandB);
break;

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

case PUSH:
cpu_ram_write(cpu, --cpu->reg[7], cpu->reg[operandA]);
break;

case POP:
cpu->reg[operandA] = cpu_ram_read(cpu, cpu->reg[7]++);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I like that you're using cpu_ram_read() and cpu_ram_write() for PUSH and POP, I think this is the more proper way of doing this. I just assigned the values directly.

break;

case CALL:
cpu_ram_write(cpu, --cpu->reg[7], ++cpu->PC);
cpu->PC = cpu->reg[operandA];
add_to_pc = 0;
break;
case RET:
cpu->PC = cpu_ram_read(cpu, cpu->reg[7]++);
break;
case CMP:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is actually an ALU operation. You can move it there if you want to. When looking at the operation codes, the third bit from the left is 1 if it is an ALU operation.

if (cpu->reg[operandA] == cpu->reg[operandB])
{
cpu->flag_reg[0] = 1;
}
else if (cpu->reg[operandA] > cpu->reg[operandB])
{
cpu->flag_reg[1] = 1;
}
else
{
cpu->flag_reg[2] = 1;
}
break;
case JMP:
cpu->PC = cpu->reg[operandA];
add_to_pc = 0;
break;
case JEQ:
if (cpu->flag_reg[0] == 1)
{
cpu->PC = cpu->reg[operandA];
add_to_pc = 0;
}
break;
case JNE:
if (cpu->flag_reg[0] == 0)
{
cpu->PC = cpu->reg[operandA];
add_to_pc = 0;
}
break;
case HLT:
running = 0;
break;
}
cpu->PC += add_to_pc;
}
}

Expand All @@ -63,5 +161,11 @@ 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->ram, 0, sizeof(cpu->ram));
memset(cpu->reg, 0, sizeof(cpu->reg));
memset(cpu->flag_reg, 0, sizeof(cpu->flag_reg));

cpu->reg[7] = 0b11110100;
}
50 changes: 27 additions & 23 deletions ls8/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,37 @@
#define _CPU_H_

// Holds all information about the CPU
struct cpu {
// TODO
// PC
// registers (array)
// ram (array)
struct cpu
{
unsigned char PC;
unsigned char flag_reg[8];
unsigned char reg[8];
unsigned char ram[256];
};

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

// Instructions

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

#define LDI 0b10000010
#define HLT 0b00000001
#define PRN 0b01000111
// TODO: more instructions here. These can be used in cpu_run().

// Function declarations
};

extern void cpu_load(struct cpu *cpu);
#define PRN 0b01000111
#define HLT 0b00000001
#define LDI 0b10000010
#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

extern void cpu_load(struct cpu *cpu, char *filename);
extern void cpu_init(struct cpu *cpu);
extern void cpu_run(struct cpu *cpu);

#endif
#endif
12 changes: 10 additions & 2 deletions ls8/ls8.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
#include <stdio.h>
#include "cpu.h"
#include <stdio.h>

/**
* Main
*/
int main(void)
int main(int argc, char **argv)
{

struct cpu cpu;

if (argc != 2)
{
fprintf(stderr, "usage: <ls8 filename.ls8>\n");
return 1;
}

cpu_init(&cpu);
cpu_load(&cpu);
cpu_load(&cpu, argv[1]);
cpu_run(&cpu);

return 0;
Expand Down