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/d84610e55772ae16/mmap_address.bin
Binary file not shown.
Binary file added .vscode/ipch/d84617e55772b9fb/cpu.ipch
Binary file not shown.
Binary file added .vscode/ipch/d84617e55772b9fb/mmap_address.bin
Binary file not shown.
Binary file added .vscode/ipch/e56e8d2c582b3ea6/ls8.ipch
Binary file not shown.
Binary file added .vscode/ipch/e56e8d2c582b3ea6/mmap_address.bin
Binary file not shown.
194 changes: 175 additions & 19 deletions ls8/cpu.c
Original file line number Diff line number Diff line change
@@ -1,60 +1,209 @@
#include "cpu.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#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
*/
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;
}
}

Expand All @@ -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;
}

22 changes: 19 additions & 3 deletions ls8/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);

Expand Down
79 changes: 79 additions & 0 deletions ls8/examples/sctest.ls8
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions ls8/ls8.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down