Merge pull request #1 from xamidev/assembler
Add: PUT instruction, Assembler separation
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
*.out
|
*.out
|
||||||
dumb8
|
dumb8
|
||||||
|
das
|
||||||
|
*.bin
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -6,11 +6,14 @@ This project is the implementation of a CPU in a high-level language, C. It aims
|
|||||||
|
|
||||||
## How to test
|
## How to test
|
||||||
|
|
||||||
You can run a test program like that. I'll try making a developer's manual so one can make its own programs using the custom assembly here.
|
You can run a test program like that. I'll try making a developer's manual so one can make its own programs using the custom assembly here.
|
||||||
|
|
||||||
|
`das` is the Dumb8 Assembler, which converts `.asm` files to `.bin` CPU executables. `dumb8` is the CPU emulator.
|
||||||
|
|
||||||
```
|
```
|
||||||
make
|
make
|
||||||
./dumb8 program.asm
|
./das program.asm
|
||||||
|
./dumb8 program.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
## Technical specifications
|
## Technical specifications
|
||||||
@@ -58,3 +61,7 @@ NOP
|
|||||||
HLT
|
HLT
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
- R0 is not usable (confusion with NOP opcode 0 in memory)
|
||||||
192
assembler/das.c
Normal file
192
assembler/das.c
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* Dumb8 code assembler
|
||||||
|
* Made by github.com/xamidev
|
||||||
|
*
|
||||||
|
* This is free and unencumbered software released into the public domain.
|
||||||
|
* For more information, please refer to <http://unlicense.org/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../cpu.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reading the assembly file and writing its instructions in
|
||||||
|
* opcode format in a binary file
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The code is not optimized at all. But remember: it is a DUMB assembler!
|
||||||
|
|
||||||
|
void assemble(char* filename)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(filename, "r");
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
printf("Cannot read file '%s'\n", filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* binary_file = strtok(filename, ".");
|
||||||
|
binary_file = strcat(binary_file, ".bin");
|
||||||
|
|
||||||
|
FILE* bin_fp = fopen(binary_file, "wb");
|
||||||
|
|
||||||
|
if (!bin_fp)
|
||||||
|
{
|
||||||
|
printf("Cannot open file '%s' for writing.\n", binary_file);
|
||||||
|
fclose(fp);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char line[256] = {0};
|
||||||
|
uint8_t buffer[BUF_MAX] = {0};
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), fp))
|
||||||
|
{
|
||||||
|
char instruction[10] = {0};
|
||||||
|
char reg1[10] = {0};
|
||||||
|
char reg2[10] = {0};
|
||||||
|
int addr = 0;
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
if (strncmp(line, ";", 1) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "\n", 1) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "HLT", 3) == 0)
|
||||||
|
{
|
||||||
|
buffer[i++] = HLT;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "NOP", 3) == 0)
|
||||||
|
{
|
||||||
|
buffer[i++] = NOP;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "MOV", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = MOV;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "ADD", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = ADD;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "CMP", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = CMP;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "SUB", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = SUB;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "OR", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = OR;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "AND", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = AND;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "XOR", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = XOR;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "JEQ", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %d", instruction, reg1, &addr);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
buffer[i++] = JEQ;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = addr;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "JMP", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %d", instruction, &addr);
|
||||||
|
buffer[i++] = JMP;
|
||||||
|
buffer[i++] = addr;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "OUT", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %s", instruction, reg1);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
buffer[i++] = OUT;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "IN", 2) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %s", instruction, reg1);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
buffer[i++] = IN;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "PUT", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %d", instruction, reg1, &value);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
buffer[i++] = PUT;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Unknown instruction '%s'\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(buffer, sizeof(uint8_t), i, bin_fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
fclose(bin_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <assembly file>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
assemble(argv[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
209
cpu.c
209
cpu.c
@@ -11,60 +11,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "cpu.h"
|
||||||
#define MEM_SIZE 256
|
|
||||||
#define NUM_REGISTERS 4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Instruction set
|
|
||||||
* Here, we're making a RISC (reduced instruction set computer)
|
|
||||||
* so we're staying minimalistic.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
// 0x00 -> No operation
|
|
||||||
NOP = 0,
|
|
||||||
|
|
||||||
// 0xA? -> Memory operations
|
|
||||||
MOV = 0xA0,
|
|
||||||
|
|
||||||
// 0xB? -> Arithmetic operations
|
|
||||||
ADD = 0xB0,
|
|
||||||
SUB = 0xB1,
|
|
||||||
|
|
||||||
// 0xC? -> Bitwise operations
|
|
||||||
OR = 0xC0,
|
|
||||||
AND = 0xC1,
|
|
||||||
XOR = 0xC2,
|
|
||||||
|
|
||||||
// 0xD? -> Input/output operations
|
|
||||||
OUT = 0xD0,
|
|
||||||
IN = 0xD1,
|
|
||||||
|
|
||||||
// 0xE? -> Jump and comparisons
|
|
||||||
JMP = 0xE0,
|
|
||||||
JEQ = 0xE1,
|
|
||||||
CMP = 0xE2,
|
|
||||||
|
|
||||||
// 0xF? -> Misc operations
|
|
||||||
HLT = 0xFF
|
|
||||||
} instruction_set_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CPU structure definition
|
|
||||||
* Contains 4 8-bit registers, memory, a program counter, a halt switch, and flags.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t reg[NUM_REGISTERS];
|
|
||||||
uint8_t memory[MEM_SIZE];
|
|
||||||
uint16_t pc;
|
|
||||||
bool halted;
|
|
||||||
bool equal_flag;
|
|
||||||
int flag_clear_delay;
|
|
||||||
} CPU_t;
|
|
||||||
|
|
||||||
CPU_t cpu;
|
CPU_t cpu;
|
||||||
|
|
||||||
@@ -91,7 +38,7 @@ void cpu_init()
|
|||||||
|
|
||||||
void cpu_exec(uint8_t opcode)
|
void cpu_exec(uint8_t opcode)
|
||||||
{
|
{
|
||||||
uint8_t reg1, reg2, addr;
|
uint8_t reg1, reg2, addr, value;
|
||||||
|
|
||||||
if (cpu.flag_clear_delay > 0)
|
if (cpu.flag_clear_delay > 0)
|
||||||
{
|
{
|
||||||
@@ -112,6 +59,11 @@ void cpu_exec(uint8_t opcode)
|
|||||||
reg2 = cpu.memory[cpu.pc++];
|
reg2 = cpu.memory[cpu.pc++];
|
||||||
cpu.reg[reg1] = cpu.reg[reg2];
|
cpu.reg[reg1] = cpu.reg[reg2];
|
||||||
break;
|
break;
|
||||||
|
case PUT:
|
||||||
|
reg1 = cpu.memory[cpu.pc++];
|
||||||
|
value = cpu.memory[cpu.pc++];
|
||||||
|
cpu.reg[reg1] = value;
|
||||||
|
break;
|
||||||
case ADD:
|
case ADD:
|
||||||
reg1 = cpu.memory[cpu.pc++];
|
reg1 = cpu.memory[cpu.pc++];
|
||||||
reg2 = cpu.memory[cpu.pc++];
|
reg2 = cpu.memory[cpu.pc++];
|
||||||
@@ -184,130 +136,32 @@ void cpu_load(const uint8_t* program, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void load_program_from_bin(char* binary_file)
|
||||||
* Reading the assembly file and writing its instructions in
|
|
||||||
* opcode format in memory
|
|
||||||
*/
|
|
||||||
|
|
||||||
void assemble(const char* filename)
|
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filename, "r");
|
FILE* binary_fp = fopen(binary_file, "rb");
|
||||||
|
|
||||||
if (!fp)
|
if (!binary_fp)
|
||||||
{
|
{
|
||||||
printf("Cannot read file '%s'\n", filename);
|
printf("Cannot open file '%s' for reading.\n", binary_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char line[256] = {0};
|
fseek(binary_fp, 0, SEEK_END);
|
||||||
size_t mem_index = 0;
|
size_t size = ftell(binary_fp);
|
||||||
|
rewind(binary_fp);
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp))
|
uint8_t* program_buffer = (uint8_t*)malloc(size);
|
||||||
{
|
if (!program_buffer)
|
||||||
char instruction[10] = {0};
|
{
|
||||||
char reg1[10] = {0};
|
printf("Memory allocation failed\n");
|
||||||
char reg2[10] = {0};
|
fclose(binary_fp);
|
||||||
int addr;
|
exit(1);
|
||||||
if (strncmp(line, ";", 1) == 0)
|
}
|
||||||
{
|
|
||||||
// comment, ignore
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (sscanf(line, "%s %[^,], %s", instruction, reg1, reg2) == 3)
|
|
||||||
{
|
|
||||||
//printf("SS1");
|
|
||||||
int reg1_n = reg1[1] - '0';
|
|
||||||
int reg2_n = reg2[1] - '0';
|
|
||||||
|
|
||||||
if (strncmp(instruction, "MOV", 3) == 0)
|
fread(program_buffer, sizeof(uint8_t), size, binary_fp);
|
||||||
{
|
cpu_load(program_buffer, size);
|
||||||
cpu.memory[mem_index++] = MOV;
|
free(program_buffer);
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
fclose(binary_fp);
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
} else if (strncmp(instruction, "ADD", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = ADD;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
} else if (strncmp(instruction, "CMP", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = CMP;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
} else if (strncmp(instruction, "SUB", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = SUB;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
}
|
|
||||||
else if (strncmp(instruction, "OR", 2) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = OR;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
}
|
|
||||||
else if (strncmp(instruction, "AND", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = AND;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
}
|
|
||||||
else if (strncmp(instruction, "XOR", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = XOR;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = reg2_n;
|
|
||||||
}
|
|
||||||
} else if (sscanf(line, "%s %[^,], %d", instruction, reg1, &addr) == 2)
|
|
||||||
{
|
|
||||||
//printf("SS2");
|
|
||||||
int reg1_n = reg1[1] - '0';
|
|
||||||
|
|
||||||
if (strncmp(instruction, "JEQ", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = JEQ;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
cpu.memory[mem_index++] = addr;
|
|
||||||
}
|
|
||||||
else if (sscanf(line, "%s %d", instruction, &addr) == 2)
|
|
||||||
{
|
|
||||||
//printf("SS3");
|
|
||||||
if (strncmp(instruction, "JMP", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = JMP;
|
|
||||||
cpu.memory[mem_index++] = addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (sscanf(line, "%s %s", instruction, reg1) == 2)
|
|
||||||
{
|
|
||||||
//printf("SS4");
|
|
||||||
int reg1_n = reg1[1] - '0';
|
|
||||||
|
|
||||||
if (strncmp(instruction, "OUT", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = OUT;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp(instruction, "IN", 2) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = IN;
|
|
||||||
cpu.memory[mem_index++] = reg1_n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (strncmp(line, "HLT", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = HLT;
|
|
||||||
}
|
|
||||||
else if (strncmp(line, "NOP", 3) == 0)
|
|
||||||
{
|
|
||||||
cpu.memory[mem_index++] = NOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -335,7 +189,7 @@ void cpu_dump()
|
|||||||
|
|
||||||
for (size_t i=0; i<NUM_REGISTERS; i++)
|
for (size_t i=0; i<NUM_REGISTERS; i++)
|
||||||
{
|
{
|
||||||
printf("R%d: 0x%x\n", i, cpu.reg[i]);
|
printf("R%lu: 0x%x\n", i, cpu.reg[i]);
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
@@ -358,6 +212,7 @@ void mem_dump()
|
|||||||
{
|
{
|
||||||
// Instructions (colored background)
|
// Instructions (colored background)
|
||||||
case 0xa0:
|
case 0xa0:
|
||||||
|
case 0xa1:
|
||||||
printf("\e[42m%02x\e[0m ", cpu.memory[i]);
|
printf("\e[42m%02x\e[0m ", cpu.memory[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -416,18 +271,14 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
{
|
{
|
||||||
printf("Usage: %s <assembly file>\n", argv[0]);
|
printf("Usage: %s <program>\n", argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
assemble(argv[1]);
|
load_program_from_bin(argv[1]);
|
||||||
|
|
||||||
// Dumping our program
|
// Dumping our program
|
||||||
mem_dump();
|
mem_dump();
|
||||||
|
|
||||||
reg_write(1, 0x68);
|
|
||||||
reg_write(2, 0x69);
|
|
||||||
reg_write(3, 0x21);
|
|
||||||
cpu_run();
|
cpu_run();
|
||||||
|
|
||||||
// Post-mortem analysis
|
// Post-mortem analysis
|
||||||
|
|||||||
60
cpu.h
Normal file
60
cpu.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#ifndef CPU_H
|
||||||
|
#define CPU_H
|
||||||
|
|
||||||
|
#define MEM_SIZE 256
|
||||||
|
#define NUM_REGISTERS 4
|
||||||
|
#define BUF_MAX 256
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Instruction set
|
||||||
|
* Here, we're making a RISC (reduced instruction set computer)
|
||||||
|
* so we're staying minimalistic.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
// 0x00 -> No operation
|
||||||
|
NOP = 0,
|
||||||
|
|
||||||
|
// 0xA? -> Memory operations
|
||||||
|
MOV = 0xA0,
|
||||||
|
PUT = 0xA1,
|
||||||
|
|
||||||
|
// 0xB? -> Arithmetic operations
|
||||||
|
ADD = 0xB0,
|
||||||
|
SUB = 0xB1,
|
||||||
|
|
||||||
|
// 0xC? -> Bitwise operations
|
||||||
|
OR = 0xC0,
|
||||||
|
AND = 0xC1,
|
||||||
|
XOR = 0xC2,
|
||||||
|
|
||||||
|
// 0xD? -> Input/output operations
|
||||||
|
OUT = 0xD0,
|
||||||
|
IN = 0xD1,
|
||||||
|
|
||||||
|
// 0xE? -> Jump and comparisons
|
||||||
|
JMP = 0xE0,
|
||||||
|
JEQ = 0xE1,
|
||||||
|
CMP = 0xE2,
|
||||||
|
|
||||||
|
// 0xF? -> Misc operations
|
||||||
|
HLT = 0xFF
|
||||||
|
} instruction_set_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CPU structure definition
|
||||||
|
* Contains 4 8-bit registers, memory, a program counter, a halt switch, and flags.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t reg[NUM_REGISTERS];
|
||||||
|
uint8_t memory[MEM_SIZE];
|
||||||
|
uint16_t pc;
|
||||||
|
bool halted;
|
||||||
|
bool equal_flag;
|
||||||
|
int flag_clear_delay;
|
||||||
|
} CPU_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
12
makefile
12
makefile
@@ -1,5 +1,11 @@
|
|||||||
all:
|
CC=gcc
|
||||||
gcc -g *.c -o dumb8
|
CFLAGS=-g -Wall -Wextra
|
||||||
|
|
||||||
|
all: asm
|
||||||
|
$(CC) *.c $(CFLAGS) -o dumb8
|
||||||
|
|
||||||
|
asm:
|
||||||
|
$(CC) assembler/*.c $(CFLAGS) -o das
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm a.out
|
rm dumb8 das
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
;this is a comment
|
;this is a comment
|
||||||
|
PUT R2, 5
|
||||||
|
MOV R1, R2
|
||||||
|
|
||||||
|
ADD R1, R2
|
||||||
|
|
||||||
OUT R1
|
|
||||||
OUT R2
|
|
||||||
OUT R3
|
|
||||||
IN R0
|
|
||||||
HLT
|
HLT
|
||||||
|
|||||||
Reference in New Issue
Block a user