Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3641e7c928 | |||
| 076d2d0b07 | |||
| 7196dfa42c | |||
|
|
52fa99817c | ||
|
|
accbdc38e7 | ||
|
|
59688d05c4 | ||
|
|
6eb02b3b58 | ||
|
|
fd0d05003e | ||
|
|
ff5e9c07d7 | ||
|
|
83efce74b9 | ||
|
|
c31fdb2f29 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
dumb8
|
dumb8
|
||||||
das
|
das
|
||||||
*.bin
|
*.bin
|
||||||
|
examples/*.bin
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -1,8 +1,11 @@
|
|||||||
# Dumb8-CPU
|
# Dumb8-CPU
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Continuing my exploration of the lower-level world...
|
Continuing my exploration of the lower-level world...
|
||||||
|
|
||||||
This project is the implementation of a CPU in a high-level language, C. It aims to have a reduced (minimalist) instruction set and still be Turing complete.
|
This project is the implementation of a CPU in a high-level language, C. It aims to have a reduced (minimalist) instruction set and still be Turing complete.
|
||||||
|
In the future, I'd like to implement it in a hardware description language such as VHDL or Verilog.
|
||||||
|
|
||||||
## How to test
|
## How to test
|
||||||
|
|
||||||
@@ -20,7 +23,7 @@ make
|
|||||||
|
|
||||||
- 8-bit processing unit
|
- 8-bit processing unit
|
||||||
- RISC (reduced instruction set computer)
|
- RISC (reduced instruction set computer)
|
||||||
- 4 general purpose registers (labeled R0 to R3)
|
- 8 general purpose registers (labeled Rx)
|
||||||
- 1 input port, 1 output port (via getchar and putchar)
|
- 1 input port, 1 output port (via getchar and putchar)
|
||||||
- Turing-completeness: bitwise and arithmetic operations
|
- Turing-completeness: bitwise and arithmetic operations
|
||||||
|
|
||||||
@@ -30,9 +33,14 @@ make
|
|||||||
; Move register RY to register RX
|
; Move register RY to register RX
|
||||||
MOV RX, RY
|
MOV RX, RY
|
||||||
|
|
||||||
; Arithmetic addition and substraction stored in RX
|
; Put value X in register RX
|
||||||
|
PUT RX, X
|
||||||
|
|
||||||
|
; Arithmetic operations. Result stored in RX
|
||||||
ADD RX, RY
|
ADD RX, RY
|
||||||
SUB RX, RY
|
SUB RX, RY
|
||||||
|
MUL RX, RY
|
||||||
|
DIV RX, RY
|
||||||
|
|
||||||
; Bitwise operations stored in RX
|
; Bitwise operations stored in RX
|
||||||
OR RX, RY
|
OR RX, RY
|
||||||
@@ -64,4 +72,4 @@ HLT
|
|||||||
|
|
||||||
## Known bugs
|
## Known bugs
|
||||||
|
|
||||||
- R0 is not usable (confusion with NOP opcode 0 in memory)
|
- If you find one, please open an issue. Contributions are highly appreciated!
|
||||||
|
|||||||
@@ -106,6 +106,24 @@ void assemble(char* filename)
|
|||||||
buffer[i++] = reg1_n;
|
buffer[i++] = reg1_n;
|
||||||
buffer[i++] = reg2_n;
|
buffer[i++] = reg2_n;
|
||||||
}
|
}
|
||||||
|
else if (strncmp(line, "MUL", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = MUL;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
|
else if (strncmp(line, "DIV", 3) == 0)
|
||||||
|
{
|
||||||
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
|
int reg1_n = reg1[1] - '0';
|
||||||
|
int reg2_n = reg2[1] - '0';
|
||||||
|
buffer[i++] = DIV;
|
||||||
|
buffer[i++] = reg1_n;
|
||||||
|
buffer[i++] = reg2_n;
|
||||||
|
}
|
||||||
else if (strncmp(line, "OR", 3) == 0)
|
else if (strncmp(line, "OR", 3) == 0)
|
||||||
{
|
{
|
||||||
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
sscanf(line, "%s %[^,], %s", instruction, reg1, reg2);
|
||||||
@@ -135,10 +153,8 @@ void assemble(char* filename)
|
|||||||
}
|
}
|
||||||
else if (strncmp(line, "JEQ", 3) == 0)
|
else if (strncmp(line, "JEQ", 3) == 0)
|
||||||
{
|
{
|
||||||
sscanf(line, "%s %[^,], %d", instruction, reg1, &addr);
|
sscanf(line, "%s %d", instruction, &addr);
|
||||||
int reg1_n = reg1[1] - '0';
|
|
||||||
buffer[i++] = JEQ;
|
buffer[i++] = JEQ;
|
||||||
buffer[i++] = reg1_n;
|
|
||||||
buffer[i++] = addr;
|
buffer[i++] = addr;
|
||||||
}
|
}
|
||||||
else if (strncmp(line, "JMP", 3) == 0)
|
else if (strncmp(line, "JMP", 3) == 0)
|
||||||
|
|||||||
38
cpu.c
38
cpu.c
@@ -26,6 +26,7 @@ void cpu_init()
|
|||||||
cpu.halted = false;
|
cpu.halted = false;
|
||||||
cpu.equal_flag = false;
|
cpu.equal_flag = false;
|
||||||
cpu.flag_clear_delay = 0;
|
cpu.flag_clear_delay = 0;
|
||||||
|
cpu.increment = 0;
|
||||||
for (size_t i=0; i<NUM_REGISTERS; i++)
|
for (size_t i=0; i<NUM_REGISTERS; i++)
|
||||||
{
|
{
|
||||||
cpu.reg[i] = 0;
|
cpu.reg[i] = 0;
|
||||||
@@ -74,6 +75,16 @@ 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 MUL:
|
||||||
|
reg1 = cpu.memory[cpu.pc++];
|
||||||
|
reg2 = cpu.memory[cpu.pc++];
|
||||||
|
cpu.reg[reg1] *= cpu.reg[reg2];
|
||||||
|
break;
|
||||||
|
case DIV:
|
||||||
|
reg1 = cpu.memory[cpu.pc++];
|
||||||
|
reg2 = cpu.memory[cpu.pc++];
|
||||||
|
cpu.reg[reg1] /= cpu.reg[reg2];
|
||||||
|
break;
|
||||||
case OR:
|
case OR:
|
||||||
reg1 = cpu.memory[cpu.pc++];
|
reg1 = cpu.memory[cpu.pc++];
|
||||||
reg2 = cpu.memory[cpu.pc++];
|
reg2 = cpu.memory[cpu.pc++];
|
||||||
@@ -97,7 +108,6 @@ void cpu_exec(uint8_t opcode)
|
|||||||
cpu.pc = addr;
|
cpu.pc = addr;
|
||||||
break;
|
break;
|
||||||
case JEQ:
|
case JEQ:
|
||||||
reg1 = cpu.memory[cpu.pc++];
|
|
||||||
addr = cpu.memory[cpu.pc++];
|
addr = cpu.memory[cpu.pc++];
|
||||||
if (cpu.equal_flag) {
|
if (cpu.equal_flag) {
|
||||||
cpu.pc = addr;
|
cpu.pc = addr;
|
||||||
@@ -122,6 +132,7 @@ void cpu_exec(uint8_t opcode)
|
|||||||
cpu.halted = true;
|
cpu.halted = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
cpu.increment++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -175,6 +186,17 @@ void cpu_run()
|
|||||||
{
|
{
|
||||||
uint8_t opcode = cpu.memory[cpu.pc++];
|
uint8_t opcode = cpu.memory[cpu.pc++];
|
||||||
cpu_exec(opcode);
|
cpu_exec(opcode);
|
||||||
|
if (cpu.pc >= MEM_SIZE)
|
||||||
|
{
|
||||||
|
printf("\nProgram ended - program counter reached max memsize\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu.increment > INF_LOOP_THRESHOLD)
|
||||||
|
{
|
||||||
|
printf("\nProgram ended - reached infinite loop threshold\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("\n[END CPU OUTPUT]\n");
|
printf("\n[END CPU OUTPUT]\n");
|
||||||
}
|
}
|
||||||
@@ -187,9 +209,9 @@ void cpu_dump()
|
|||||||
{
|
{
|
||||||
printf("\n*** CPU state dump ***\nPC: 0x%x\nEqual flag: %d\nHalted: %d\n\n", cpu.pc, cpu.equal_flag, cpu.halted);
|
printf("\n*** CPU state dump ***\nPC: 0x%x\nEqual flag: %d\nHalted: %d\n\n", cpu.pc, cpu.equal_flag, cpu.halted);
|
||||||
|
|
||||||
for (size_t i=0; i<NUM_REGISTERS; i++)
|
for (size_t i=0; i<NUM_REGISTERS; i+=2)
|
||||||
{
|
{
|
||||||
printf("R%lu: 0x%x\n", i, cpu.reg[i]);
|
printf("R%lu: 0x%04x R%lu: 0x%04x\n", i, cpu.reg[i], i+1, cpu.reg[i+1]);
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
@@ -200,12 +222,12 @@ void cpu_dump()
|
|||||||
|
|
||||||
void mem_dump()
|
void mem_dump()
|
||||||
{
|
{
|
||||||
printf("\n*** Memory dump ***\n");
|
printf("\n*** Memory dump ***");
|
||||||
for (size_t i=0; i<MEM_SIZE; i++)
|
for (size_t i=0; i<MEM_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (i%20 == 0)
|
if (i%20 == 0)
|
||||||
{
|
{
|
||||||
puts("");
|
printf("\n%04ld: ", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cpu.memory[i])
|
switch (cpu.memory[i])
|
||||||
@@ -218,6 +240,8 @@ void mem_dump()
|
|||||||
|
|
||||||
case 0xb0:
|
case 0xb0:
|
||||||
case 0xb1:
|
case 0xb1:
|
||||||
|
case 0xb2:
|
||||||
|
case 0xb3:
|
||||||
printf("\e[43m%02x\e[0m ", cpu.memory[i]);
|
printf("\e[43m%02x\e[0m ", cpu.memory[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -242,10 +266,14 @@ void mem_dump()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// General purpose registers (colored foreground)
|
// General purpose registers (colored foreground)
|
||||||
|
//case 0x00:
|
||||||
case 0x01:
|
case 0x01:
|
||||||
case 0x02:
|
case 0x02:
|
||||||
case 0x03:
|
case 0x03:
|
||||||
case 0x04:
|
case 0x04:
|
||||||
|
case 0x05:
|
||||||
|
case 0x06:
|
||||||
|
case 0x07:
|
||||||
printf("\e[36m%02x\e[0m ", cpu.memory[i]);
|
printf("\e[36m%02x\e[0m ", cpu.memory[i]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
12
cpu.h
12
cpu.h
@@ -2,8 +2,9 @@
|
|||||||
#define CPU_H
|
#define CPU_H
|
||||||
|
|
||||||
#define MEM_SIZE 256
|
#define MEM_SIZE 256
|
||||||
#define NUM_REGISTERS 4
|
#define NUM_REGISTERS 8
|
||||||
#define BUF_MAX 256
|
#define BUF_MAX 256
|
||||||
|
#define INF_LOOP_THRESHOLD 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instruction set
|
* Instruction set
|
||||||
@@ -13,9 +14,6 @@
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
// 0x00 -> No operation
|
|
||||||
NOP = 0,
|
|
||||||
|
|
||||||
// 0xA? -> Memory operations
|
// 0xA? -> Memory operations
|
||||||
MOV = 0xA0,
|
MOV = 0xA0,
|
||||||
PUT = 0xA1,
|
PUT = 0xA1,
|
||||||
@@ -23,6 +21,8 @@ typedef enum
|
|||||||
// 0xB? -> Arithmetic operations
|
// 0xB? -> Arithmetic operations
|
||||||
ADD = 0xB0,
|
ADD = 0xB0,
|
||||||
SUB = 0xB1,
|
SUB = 0xB1,
|
||||||
|
MUL = 0xB2,
|
||||||
|
DIV = 0xB3,
|
||||||
|
|
||||||
// 0xC? -> Bitwise operations
|
// 0xC? -> Bitwise operations
|
||||||
OR = 0xC0,
|
OR = 0xC0,
|
||||||
@@ -39,12 +39,13 @@ typedef enum
|
|||||||
CMP = 0xE2,
|
CMP = 0xE2,
|
||||||
|
|
||||||
// 0xF? -> Misc operations
|
// 0xF? -> Misc operations
|
||||||
|
NOP = 0xFE,
|
||||||
HLT = 0xFF
|
HLT = 0xFF
|
||||||
} instruction_set_t;
|
} instruction_set_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CPU structure definition
|
* CPU structure definition
|
||||||
* Contains 4 8-bit registers, memory, a program counter, a halt switch, and flags.
|
* Contains 8-bit registers, memory, a program counter, a halt switch, and flags.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -55,6 +56,7 @@ typedef struct
|
|||||||
bool halted;
|
bool halted;
|
||||||
bool equal_flag;
|
bool equal_flag;
|
||||||
int flag_clear_delay;
|
int flag_clear_delay;
|
||||||
|
int increment;
|
||||||
} CPU_t;
|
} CPU_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
48
examples/hello.asm
Normal file
48
examples/hello.asm
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
; Hello, world!
|
||||||
|
|
||||||
|
PUT R1, 72
|
||||||
|
PUT R2, 101
|
||||||
|
PUT R3, 108
|
||||||
|
|
||||||
|
OUT R1
|
||||||
|
OUT R2
|
||||||
|
OUT R3
|
||||||
|
OUT R3
|
||||||
|
|
||||||
|
XOR R1, R1
|
||||||
|
XOR R2, R2
|
||||||
|
XOR R3, R3
|
||||||
|
|
||||||
|
PUT R1, 111
|
||||||
|
PUT R2, 44
|
||||||
|
PUT R3, 32
|
||||||
|
|
||||||
|
OUT R1
|
||||||
|
OUT R2
|
||||||
|
OUT R3
|
||||||
|
|
||||||
|
XOR R1, R1
|
||||||
|
XOR R2, R2
|
||||||
|
XOR R3, R3
|
||||||
|
|
||||||
|
PUT R1, 119
|
||||||
|
PUT R2, 111
|
||||||
|
PUT R3, 114
|
||||||
|
|
||||||
|
OUT R1
|
||||||
|
OUT R2
|
||||||
|
OUT R3
|
||||||
|
|
||||||
|
XOR R1, R1
|
||||||
|
XOR R2, R2
|
||||||
|
XOR R3, R3
|
||||||
|
|
||||||
|
PUT R1, 108
|
||||||
|
PUT R2, 100
|
||||||
|
PUT R3, 33
|
||||||
|
|
||||||
|
OUT R1
|
||||||
|
OUT R2
|
||||||
|
OUT R3
|
||||||
|
|
||||||
|
HLT
|
||||||
10
examples/looptext.asm
Normal file
10
examples/looptext.asm
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
; Loop a "Hi!"
|
||||||
|
|
||||||
|
PUT R1, 104
|
||||||
|
PUT R2, 105
|
||||||
|
PUT R3, 32
|
||||||
|
OUT R1
|
||||||
|
OUT R2
|
||||||
|
OUT R3
|
||||||
|
JMP 0
|
||||||
|
HLT
|
||||||
4
makefile
4
makefile
@@ -7,5 +7,9 @@ all: asm
|
|||||||
asm:
|
asm:
|
||||||
$(CC) assembler/*.c $(CFLAGS) -o das
|
$(CC) assembler/*.c $(CFLAGS) -o das
|
||||||
|
|
||||||
|
run:
|
||||||
|
./das program.asm
|
||||||
|
./dumb8 program.bin
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm dumb8 das
|
rm dumb8 das
|
||||||
|
|||||||
11
program.asm
11
program.asm
@@ -1,7 +1,10 @@
|
|||||||
;this is a comment
|
;this is a comment
|
||||||
PUT R2, 5
|
|
||||||
MOV R1, R2
|
|
||||||
|
|
||||||
ADD R1, R2
|
|
||||||
|
|
||||||
|
PUT R0, 2
|
||||||
|
PUT R1, 2
|
||||||
|
CMP R0, R1
|
||||||
|
JEQ 12
|
||||||
|
HLT
|
||||||
|
|
||||||
|
PUT R7, 10
|
||||||
HLT
|
HLT
|
||||||
|
|||||||
Reference in New Issue
Block a user