diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..e0a85ca --- /dev/null +++ b/.cproject @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.directory b/.directory new file mode 100644 index 0000000..83ab9e3 --- /dev/null +++ b/.directory @@ -0,0 +1,3 @@ +[Dolphin] +Timestamp=2019,11,27,21,50,31 +Version=4 diff --git a/.project b/.project new file mode 100644 index 0000000..51f0265 --- /dev/null +++ b/.project @@ -0,0 +1,26 @@ + + + CHIP8-EMU + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 0000000..be97d5f --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Debug/CHIP8-EMU b/Debug/CHIP8-EMU new file mode 100755 index 0000000..6c3eaad Binary files /dev/null and b/Debug/CHIP8-EMU differ diff --git a/Debug/makefile b/Debug/makefile new file mode 100644 index 0000000..4c7abef --- /dev/null +++ b/Debug/makefile @@ -0,0 +1,43 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +-include ../makefile.init + +RM := rm -rf + +# All of the sources participating in the build are defined here +-include sources.mk +-include src/subdir.mk +-include subdir.mk +-include objects.mk + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) +endif +endif + +-include ../makefile.defs + +# Add inputs and outputs from these tool invocations to the build variables + +# All Target +all: CHIP8-EMU + +# Tool invocations +CHIP8-EMU: $(OBJS) $(USER_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GCC C Linker' + gcc -o "CHIP8-EMU" $(OBJS) $(USER_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +# Other Targets +clean: + -$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) CHIP8-EMU + -@echo ' ' + +.PHONY: all clean dependents + +-include ../makefile.targets diff --git a/Debug/objects.mk b/Debug/objects.mk new file mode 100644 index 0000000..54b7836 --- /dev/null +++ b/Debug/objects.mk @@ -0,0 +1,8 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +USER_OBJS := + +LIBS := -lncurses + diff --git a/Debug/sources.mk b/Debug/sources.mk new file mode 100644 index 0000000..a1c58f7 --- /dev/null +++ b/Debug/sources.mk @@ -0,0 +1,17 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +OBJ_SRCS := +ASM_SRCS := +C_SRCS := +O_SRCS := +S_UPPER_SRCS := +EXECUTABLES := +OBJS := +C_DEPS := + +# Every subdirectory with source files must be described here +SUBDIRS := \ +src \ + diff --git a/Debug/src/chip8.d b/Debug/src/chip8.d new file mode 100644 index 0000000..b83fd48 --- /dev/null +++ b/Debug/src/chip8.d @@ -0,0 +1,3 @@ +src/chip8.o: ../src/chip8.c ../src/include/chip8.h + +../src/include/chip8.h: diff --git a/Debug/src/chip8.o b/Debug/src/chip8.o new file mode 100644 index 0000000..f28069b Binary files /dev/null and b/Debug/src/chip8.o differ diff --git a/Debug/src/main.d b/Debug/src/main.d new file mode 100644 index 0000000..b93fd95 --- /dev/null +++ b/Debug/src/main.d @@ -0,0 +1,3 @@ +src/main.o: ../src/main.c ../src/include/chip8.h + +../src/include/chip8.h: diff --git a/Debug/src/main.o b/Debug/src/main.o new file mode 100644 index 0000000..c994a39 Binary files /dev/null and b/Debug/src/main.o differ diff --git a/Debug/src/subdir.mk b/Debug/src/subdir.mk new file mode 100644 index 0000000..c7e9041 --- /dev/null +++ b/Debug/src/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/chip8.c \ +../src/main.c + +OBJS += \ +./src/chip8.o \ +./src/main.o + +C_DEPS += \ +./src/chip8.d \ +./src/main.d + + +# Each subdirectory must supply rules for building sources it contributes +src/%.o: ../src/%.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/README.md b/README.md index 2d1812f..a2bfba8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ # CHIP8-EMU -A CHIP8 emulator written in C. \ No newline at end of file +A CHIP8 emulator written in C. + +## Eclipse IDE import: + +> File > Import > Existing Code as Makefile project + +## Building: +Eclispe IDE: +> Right click project > Build Project. + +Terminal: +> cd Debug +> make + +## Running: +> ./CHIP8-EMU \ + +## Known issues: + - [] Implement key pad + diff --git a/roms/15PUZZLE b/roms/15PUZZLE new file mode 100644 index 0000000..3ef0bc8 Binary files /dev/null and b/roms/15PUZZLE differ diff --git a/roms/BLINKY b/roms/BLINKY new file mode 100644 index 0000000..235cf98 Binary files /dev/null and b/roms/BLINKY differ diff --git a/roms/BLITZ b/roms/BLITZ new file mode 100644 index 0000000..0d2effa Binary files /dev/null and b/roms/BLITZ differ diff --git a/roms/BRIX b/roms/BRIX new file mode 100644 index 0000000..ad639d9 Binary files /dev/null and b/roms/BRIX differ diff --git a/roms/CONNECT4 b/roms/CONNECT4 new file mode 100644 index 0000000..200a67a Binary files /dev/null and b/roms/CONNECT4 differ diff --git a/roms/GUESS b/roms/GUESS new file mode 100644 index 0000000..36f783d Binary files /dev/null and b/roms/GUESS differ diff --git a/roms/HIDDEN b/roms/HIDDEN new file mode 100644 index 0000000..bd6b18d Binary files /dev/null and b/roms/HIDDEN differ diff --git a/roms/INVADERS b/roms/INVADERS new file mode 100644 index 0000000..f7db5f5 Binary files /dev/null and b/roms/INVADERS differ diff --git a/roms/KALEID b/roms/KALEID new file mode 100644 index 0000000..a1bc7cc Binary files /dev/null and b/roms/KALEID differ diff --git a/roms/MAZE b/roms/MAZE new file mode 100644 index 0000000..152ae7d Binary files /dev/null and b/roms/MAZE differ diff --git a/roms/MERLIN b/roms/MERLIN new file mode 100644 index 0000000..747843a Binary files /dev/null and b/roms/MERLIN differ diff --git a/roms/MISSILE b/roms/MISSILE new file mode 100644 index 0000000..310e2de Binary files /dev/null and b/roms/MISSILE differ diff --git a/roms/PONG b/roms/PONG new file mode 100644 index 0000000..e371e91 Binary files /dev/null and b/roms/PONG differ diff --git a/roms/PONG2 b/roms/PONG2 new file mode 100644 index 0000000..295ce91 Binary files /dev/null and b/roms/PONG2 differ diff --git a/roms/PUZZLE b/roms/PUZZLE new file mode 100644 index 0000000..bec7af0 Binary files /dev/null and b/roms/PUZZLE differ diff --git a/roms/SYZYGY b/roms/SYZYGY new file mode 100644 index 0000000..b0653ef Binary files /dev/null and b/roms/SYZYGY differ diff --git a/roms/TANK b/roms/TANK new file mode 100644 index 0000000..ca4bbab Binary files /dev/null and b/roms/TANK differ diff --git a/roms/TETRIS b/roms/TETRIS new file mode 100644 index 0000000..9f5e087 Binary files /dev/null and b/roms/TETRIS differ diff --git a/roms/TICTAC b/roms/TICTAC new file mode 100644 index 0000000..4d4bc99 Binary files /dev/null and b/roms/TICTAC differ diff --git a/roms/UFO b/roms/UFO new file mode 100644 index 0000000..7fa5a15 Binary files /dev/null and b/roms/UFO differ diff --git a/roms/VBRIX b/roms/VBRIX new file mode 100644 index 0000000..07f4006 Binary files /dev/null and b/roms/VBRIX differ diff --git a/roms/VERS b/roms/VERS new file mode 100644 index 0000000..b0fe240 Binary files /dev/null and b/roms/VERS differ diff --git a/roms/WIPEOFF b/roms/WIPEOFF new file mode 100644 index 0000000..2d5e513 Binary files /dev/null and b/roms/WIPEOFF differ diff --git a/roms/rom.bin b/roms/rom.bin new file mode 100644 index 0000000..0dca981 Binary files /dev/null and b/roms/rom.bin differ diff --git a/src/chip8.c b/src/chip8.c new file mode 100644 index 0000000..0c2a84c --- /dev/null +++ b/src/chip8.c @@ -0,0 +1,388 @@ +#include "include/chip8.h" +#include +#include +#include + +int chip8_dump(chip8_t *chip, const char *filename) { + if (chip == NULL) + return -1; + if (filename == NULL) + return -2; + + FILE *file = fopen(filename, "w"); + if (file == NULL) + return -3; + + uint16_t i; + fprintf(file, "CHIP8 DUMP FILE\n\n"); + fprintf(file, "REGISTERS:\n V: "); + for (i = 0; i < 16; i++) { + fprintf(file, "%02x", chip->cpu.V[i]); + if (i < 15) + fprintf(file, " "); + else + fprintf(file, "\n"); + } + fprintf(file, " SP: %02x\n", chip->cpu.SP); + fprintf(file, " TS: %02x\n", chip->cpu.TS); + fprintf(file, " TD: %02x\n", chip->cpu.TD); + fprintf(file, " PC: %04x\n", chip->cpu.PC); + fprintf(file, " I: %04x\n\n", chip->cpu.I); + fprintf(file, "MEMORY:\n RAM: "); + for (i = 0; i < 4096; i++) { + fprintf(file, "%02x", chip->mem.RAM[i]); + if (i % 64 < 63) { + if (i == chip->cpu.PC - 1) + fprintf(file, "["); + else if (i == chip->cpu.PC + 1) + fprintf(file, "]"); + else if (i == chip->cpu.I) + fprintf(file, "-"); + else + fprintf(file, " "); + } else { + fprintf(file, " %04x | %04x\n", i - 63, i); + if (i < 4095) + fprintf(file, " "); + } + } + fprintf(file, " STK: "); + for (i = 0; i < 24; i++) { + fprintf(file, "%04x", chip->mem.STK[i]); + if (i < 23) + fprintf(file, " "); + else + fprintf(file, "\n"); + } + fprintf(file, "\nIO:\n KEYS: "); + for (i = 0; i < 24; i++) { + fprintf(file, "%02x", chip->io.KEYS[i]); + if (i < 23) + fprintf(file, " "); + else + fprintf(file, "\n"); + } + fprintf(file, " DSP: "); + for (i = 0; i < 2048; i++) { + fprintf(file, "%s", chip->io.DSP[i] ? "XX" : ".."); + if (i % 64 == 63) { + fprintf(file, "\n"); + if (i < 2047) + fprintf(file, " "); + } + } + + fclose(file); + + return 0; +} + +int chip8_init(chip8_t *chip) { + if (chip == NULL) + return -1; + + uint16_t i; + + for (i = 0; i < 16; i++) + chip->cpu.V[i] = 0x00; + chip->cpu.SP = 0x00; + chip->cpu.TS = 0x00; + chip->cpu.TD = 0x00; + chip->cpu.PC = 0x0200; + chip->cpu.I = 0x0000; + + for (i = 0; i < 4096; i++) + chip->mem.RAM[i] = 0x00; + for (i = 0; i < 24; i++) + chip->mem.STK[i] = 0x00; + //font "0" + chip->mem.RAM[0] = 0b11110000; + chip->mem.RAM[1] = 0b10010000; + chip->mem.RAM[2] = 0b10010000; + chip->mem.RAM[3] = 0b10010000; + chip->mem.RAM[4] = 0b11110000; + //font "1" + chip->mem.RAM[5] = 0b00100000; + chip->mem.RAM[6] = 0b01100000; + chip->mem.RAM[7] = 0b00100000; + chip->mem.RAM[8] = 0b00100000; + chip->mem.RAM[9] = 0b01110000; + //font "2" + chip->mem.RAM[10] = 0b11110000; + chip->mem.RAM[11] = 0b00010000; + chip->mem.RAM[12] = 0b11110000; + chip->mem.RAM[13] = 0b10000000; + chip->mem.RAM[14] = 0b11110000; + //font "3" + chip->mem.RAM[15] = 0b11110000; + chip->mem.RAM[16] = 0b00010000; + chip->mem.RAM[17] = 0b11110000; + chip->mem.RAM[18] = 0b00010000; + chip->mem.RAM[19] = 0b11110000; + //font "4" + chip->mem.RAM[20] = 0b10010000; + chip->mem.RAM[21] = 0b10010000; + chip->mem.RAM[22] = 0b11110000; + chip->mem.RAM[23] = 0b00010000; + chip->mem.RAM[24] = 0b00010000; + //font "5" + chip->mem.RAM[25] = 0b11110000; + chip->mem.RAM[26] = 0b10000000; + chip->mem.RAM[27] = 0b11110000; + chip->mem.RAM[28] = 0b00010000; + chip->mem.RAM[29] = 0b11110000; + //font "6" + chip->mem.RAM[30] = 0b11110000; + chip->mem.RAM[31] = 0b10000000; + chip->mem.RAM[32] = 0b11110000; + chip->mem.RAM[33] = 0b10010000; + chip->mem.RAM[34] = 0b11110000; + //font "7" + chip->mem.RAM[35] = 0b11110000; + chip->mem.RAM[36] = 0b00010000; + chip->mem.RAM[37] = 0b00100000; + chip->mem.RAM[38] = 0b01000000; + chip->mem.RAM[39] = 0b01000000; + //font "8" + chip->mem.RAM[40] = 0b11110000; + chip->mem.RAM[41] = 0b10010000; + chip->mem.RAM[42] = 0b11110000; + chip->mem.RAM[43] = 0b10010000; + chip->mem.RAM[44] = 0b11110000; + //font "9" + chip->mem.RAM[45] = 0b11110000; + chip->mem.RAM[46] = 0b10010000; + chip->mem.RAM[47] = 0b11110000; + chip->mem.RAM[48] = 0b00010000; + chip->mem.RAM[49] = 0b11110000; + //font "A" + chip->mem.RAM[50] = 0b11110000; + chip->mem.RAM[51] = 0b10010000; + chip->mem.RAM[52] = 0b11110000; + chip->mem.RAM[53] = 0b10010000; + chip->mem.RAM[54] = 0b10010000; + //font "B" + chip->mem.RAM[55] = 0b11100000; + chip->mem.RAM[56] = 0b10010000; + chip->mem.RAM[57] = 0b11100000; + chip->mem.RAM[58] = 0b10010000; + chip->mem.RAM[59] = 0b11100000; + //font "C" + chip->mem.RAM[60] = 0b11110000; + chip->mem.RAM[61] = 0b10000000; + chip->mem.RAM[62] = 0b10000000; + chip->mem.RAM[63] = 0b10000000; + chip->mem.RAM[64] = 0b11110000; + //font "D" + chip->mem.RAM[65] = 0b11100000; + chip->mem.RAM[66] = 0b10010000; + chip->mem.RAM[67] = 0b10010000; + chip->mem.RAM[68] = 0b10010000; + chip->mem.RAM[69] = 0b11100000; + //font "E" + chip->mem.RAM[70] = 0b11110000; + chip->mem.RAM[71] = 0b10000000; + chip->mem.RAM[72] = 0b11110000; + chip->mem.RAM[73] = 0b10000000; + chip->mem.RAM[74] = 0b11110000; + //font "F" + chip->mem.RAM[75] = 0b11110000; + chip->mem.RAM[76] = 0b10000000; + chip->mem.RAM[77] = 0b11110000; + chip->mem.RAM[78] = 0b10000000; + chip->mem.RAM[79] = 0b10000000; + + for (i = 0; i < 16; i++) + chip->io.KEYS[i] = 0x00; + for (i = 0; i < 2048; i++) + chip->io.DSP[i] = 0x00; + + chip->flags.draw = 0x00; + + return 0; +} + +int chip8_load(chip8_t *chip, const char *filename) { + if (chip == NULL) + return -1; + if (filename == NULL) + return -2; + + FILE *file = fopen(filename, "rb"); + if (file == NULL) + return -3; + + fseek(file, 0L, SEEK_END); + long size = ftell(file); + if (size < 1L) { + fclose(file); + return -4; + } + fseek(file, 0L, SEEK_SET); + if (fread(chip->mem.RAM + 0x200, 1, size, file) < size) { + fclose(file); + return -5; + } + fclose(file); + + return 0; +} + +int chip8_cycle(chip8_t *chip) { + uint16_t opcode = (chip->mem.RAM[chip->cpu.PC] << 8) | chip->mem.RAM[chip->cpu.PC + 1]; + uint8_t nibble[4] = { opcode >> 12, (opcode >> 8) & 0x000F, (opcode >> 4) & 0x000F, opcode & 0x000F }; + + uint16_t i; + + if (opcode == 0x00E0) { + for (i = 0; i < 2048; i++) + chip->io.DSP[i] = 0x00; + chip->flags.draw = 0x01; + chip->cpu.PC += 2; + } else if (opcode == 0x00EE) { + chip->cpu.SP--; + chip->cpu.PC = chip->mem.STK[chip->cpu.SP] + 2; + } else if (nibble[0] == 0x01) { + chip->cpu.PC = opcode & 0x0FFF; + } else if (nibble[0] == 0x02) { + chip->mem.STK[chip->cpu.SP] = chip->cpu.PC; + chip->cpu.SP++; + chip->cpu.PC = opcode & 0x0FFF; + } else if (nibble[0] == 0x03) { + if (chip->cpu.V[nibble[1]] == (opcode & 0x00FF)) + chip->cpu.PC += 2; + chip->cpu.PC += 2; + } else if (nibble[0] == 0x04) { + if (chip->cpu.V[nibble[1]] != (opcode & 0x00FF)) + chip->cpu.PC += 2; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x5000) { + if (chip->cpu.V[nibble[1]] == chip->cpu.V[nibble[2]]) + chip->cpu.PC += 2; + chip->cpu.PC += 2; + } else if (nibble[0] == 0x06) { + chip->cpu.V[nibble[1]] = opcode & 0x00FF; + chip->cpu.PC += 2; + } else if (nibble[0] == 0x07) { + chip->cpu.V[nibble[1]] += opcode & 0x00FF; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8000) { + chip->cpu.V[nibble[1]] = chip->cpu.V[nibble[2]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8001) { + chip->cpu.V[nibble[1]] |= chip->cpu.V[nibble[2]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8002) { + chip->cpu.V[nibble[1]] &= chip->cpu.V[nibble[2]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8003) { + chip->cpu.V[nibble[1]] ^= chip->cpu.V[nibble[2]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8004) { + if ((uint16_t) chip->cpu.V[nibble[1]] + (uint16_t) chip->cpu.V[nibble[2]] > 0x00FF) + chip->cpu.V[0xF] = 0x01; + else + chip->cpu.V[0xF] = 0x00; + chip->cpu.V[nibble[1]] += chip->cpu.V[nibble[2]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8005) { + if (chip->cpu.V[nibble[1]] > chip->cpu.V[nibble[2]]) + chip->cpu.V[0xF] = 0x01; + else + chip->cpu.V[0xF] = 0x00; + chip->cpu.V[nibble[1]] -= chip->cpu.V[nibble[2]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8006) { + chip->cpu.V[0x0F] = chip->cpu.V[nibble[1]] & 0x01; + chip->cpu.V[nibble[1]] >>= 1; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x8007) { + if (chip->cpu.V[nibble[2]] > chip->cpu.V[nibble[1]]) + chip->cpu.V[0xF] = 0x01; + else + chip->cpu.V[0xF] = 0x00; + chip->cpu.V[nibble[1]] = chip->cpu.V[nibble[2]] - chip->cpu.V[nibble[1]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x800E) { + chip->cpu.V[0x0F] = chip->cpu.V[nibble[1]] & 0x80; + chip->cpu.V[nibble[1]] <<= 1; + chip->cpu.PC += 2; + } else if ((opcode & 0xF00F) == 0x9000) { + if (chip->cpu.V[nibble[1]] != chip->cpu.V[nibble[2]]) + chip->cpu.PC += 2; + chip->cpu.PC += 2; + } else if (nibble[0] == 0x0A) { + chip->cpu.I = opcode & 0x0FFF; + chip->cpu.PC += 2; + } else if (nibble[0] == 0x0B) { + chip->cpu.PC = (opcode & 0x0FFF) + chip->cpu.V[0x00]; + } else if (nibble[0] == 0x0C) { + chip->cpu.V[nibble[1]] = (rand() % 256) & (opcode & 0x00FF); + chip->cpu.PC += 2; + } else if (nibble[0] == 0x0D) { + uint8_t j, last, x = chip->cpu.V[nibble[1]], y = chip->cpu.V[nibble[2]]; + chip->cpu.V[0x0F] = 0x00; + for (i = 0; i < nibble[3]; i++) { + for (j = 0; j < 8; j++) { + last = chip->io.DSP[(y + i) * 64 + x + j]; + chip->io.DSP[(y + i) * 64 + x + j] ^= (chip->mem.RAM[chip->cpu.I + i] >> (7 - j)) & 0x01; + if (!chip->io.DSP[(y + i) * 64 + x + j] && last) + chip->cpu.V[0x0F] = 0x01; + + } + } + chip->flags.draw = 0x01; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xE09E) { + if (chip->io.KEYS[nibble[1]]) + chip->cpu.PC += 2; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xE0A1) { + if (!(chip->io.KEYS[nibble[1]])) + chip->cpu.PC += 2; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF007) { + chip->cpu.V[nibble[1]] = chip->cpu.TD; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF00A) { + for (i = 0; i < 16; i++) + if (chip->io.KEYS[i]) { + chip->cpu.PC += 2; + break; + } + } else if ((opcode & 0xF0FF) == 0xF015) { + chip->cpu.TD = chip->cpu.V[nibble[1]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF018) { + chip->cpu.TS = chip->cpu.V[nibble[1]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF01E) { + chip->cpu.V[0x0F] = chip->cpu.I + (uint16_t) chip->cpu.V[nibble[1]] > 0x0FFF; + chip->cpu.I += chip->cpu.V[nibble[1]]; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF029) { + chip->cpu.I = nibble[1] * 5; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF033) { + chip->mem.RAM[chip->cpu.I] = chip->cpu.V[nibble[1]] / 100; + chip->mem.RAM[chip->cpu.I + 1] = (chip->cpu.V[nibble[1]] / 10) % 10; + chip->mem.RAM[chip->cpu.I + 2] = chip->cpu.V[nibble[1]] % 10; + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF055) { + for (i = 0; i < nibble[1]; i++) { + chip->mem.RAM[chip->cpu.I] = chip->cpu.V[i]; + chip->cpu.I++; + } + chip->cpu.PC += 2; + } else if ((opcode & 0xF0FF) == 0xF065) { + for (i = 0; i < nibble[1]; i++) { + chip->cpu.V[i] = chip->mem.RAM[chip->cpu.I]; + chip->cpu.I++; + } + chip->cpu.PC += 2; + } else { + return -1; + } + + return 0; +} diff --git a/src/include/chip8.h b/src/include/chip8.h new file mode 100644 index 0000000..7f95646 --- /dev/null +++ b/src/include/chip8.h @@ -0,0 +1,28 @@ +#ifndef SRC_INCLUDE_CHIP8_H_ +#define SRC_INCLUDE_CHIP8_H_ + +#include + +typedef struct { + struct { + uint8_t V[16], SP, TS, TD; + uint16_t PC, I; + } cpu; + struct { + uint8_t RAM[4096]; + uint16_t STK[24]; + } mem; + struct { + uint8_t KEYS[16], DSP[2048]; + } io; + struct { + uint8_t draw; + } flags; +} chip8_t; + +int chip8_dump(chip8_t *, const char *); +int chip8_init(chip8_t *); +int chip8_load(chip8_t *, const char *); +int chip8_cycle(chip8_t *); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1bc57de --- /dev/null +++ b/src/main.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include "include/chip8.h" + +void chip8_keys_clear(chip8_t *chip) { + for (uint8_t i = 0; i < 16; i++) + chip->io.KEYS[i] = 0x00; +} + +int main(int argc, char **argv) { + + if (argc < 2) { + printf("No ROM files specified!\n"); + return -1; + } + + chip8_t chip; + chip8_init(&chip); + srand(time(NULL)); + chip8_load(&chip, argv[1]); + + struct timespec ts = { .tv_nsec = 2000000, .tv_sec = 0 }; + float timer_delay = 0.0F, timer_sound = 0.0F; + + noecho(); + cbreak(); + timeout(0); + int ch; + + while (1) { + + for (int i = 0; i < 16; i++) + chip.io.KEYS[i] = 0x01; + + ch = getch(); + chip8_keys_clear(&chip); + switch (ch) { + case '1': + chip.io.KEYS[0x1] = 0x01; + break; + case '2': + chip.io.KEYS[0x2] = 0x01; + break; + case '3': + chip.io.KEYS[0x3] = 0x01; + break; + case '4': + chip.io.KEYS[0xC] = 0x01; + break; + case 'q': + chip.io.KEYS[0x4] = 0x01; + break; + case 'w': + chip.io.KEYS[0x5] = 0x01; + break; + case 'e': + chip.io.KEYS[0x6] = 0x01; + break; + case 'r': + chip.io.KEYS[0xD] = 0x01; + break; + case 'a': + chip.io.KEYS[0x7] = 0x01; + break; + case 's': + chip.io.KEYS[0x8] = 0x01; + break; + case 'd': + chip.io.KEYS[0x9] = 0x01; + break; + case 'f': + chip.io.KEYS[0xE] = 0x01; + break; + case 'z': + chip.io.KEYS[0xA] = 0x01; + break; + case 'x': + chip.io.KEYS[0x0] = 0x01; + break; + case 'c': + chip.io.KEYS[0xB] = 0x01; + break; + case 'v': + chip.io.KEYS[0xF] = 0x01; + break; + default: + break; + } + + if (chip.cpu.TD) { + timer_delay += 2.0F; + if (timer_delay >= 1000.0F / 60.0F) { + timer_delay -= 1000.0F / 60.0F; + chip.cpu.TD--; + if (chip.cpu.TD == 0) + timer_delay = 0.0F; + } + } + + if (chip.cpu.TS) { + timer_sound += 2.0F; + if (timer_sound >= 1000.0F / 60.0F) { + timer_sound -= 1000.0F / 60.0F; + chip.cpu.TS--; + if (chip.cpu.TS == 0) + timer_sound = 0.0F; + } + } + + if (chip.flags.draw) { + chip.flags.draw = 0x00; + printf("\033[0;0H"); + for (int x = 0; x < 66; x++) + printf("##"); + printf("\n"); + for (int y = 0; y < 32; y++) { + printf("##"); + for (int x = 0; x < 64; x++) { + if (chip.io.DSP[y * 64 + x]) + printf("██"); + else + printf(" "); + } + printf("##\n"); + } + for (int x = 0; x < 66; x++) + printf("##"); + printf("\n"); + } + + if (chip8_cycle(&chip)) { + printf("Invalid opcode 0x%04x!\n", (chip.mem.RAM[chip.cpu.PC] << 8) | chip.mem.RAM[chip.cpu.PC + 1]); + return -2; + } + + nanosleep(&ts, &ts); + ts.tv_nsec = 2000000; + ts.tv_sec = 0; + } + + return 0; +}