commit 2fb9be227d168cd44ddcf669f3002be7c2ccf4b7 Author: Alice Date: Mon Feb 17 19:15:19 2020 +0100 First commit. Way too much.. Sould have done this sooner... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ab7c7b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build-*/ +*.ch8 +*.g*a diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..94fd233 --- /dev/null +++ b/Makefile @@ -0,0 +1,194 @@ +#! /usr/bin/make -f +# Default Makefile for fxSDK add-ins. This file was probably copied there by +# the [fxsdk] program. +#--- + +# +# Configuration +# + +include project.cfg + +# Compiler flags +CFLAGSFX := $(CFLAGS) $(CFLAGS_FX) $(INCLUDE) +CFLAGSCG := $(CFLAGS) $(CFLAGS_CG) $(INCLUDE) + +# Linker flags +LDFLAGSFX := $(LDFLAGS) $(LDFLAGS_FX) +LDFLAGSCG := $(LDFLAGS) $(LDFLAGS_CG) + +# Dependency list generation flags +depflags = -MMD -MT $@ -MF $(@:.o=.d) -MP +# ELF to binary flags +BINFLAGS := -R .bss -R .gint_bss + +# G1A and G3A generation flags +NAME_G1A ?= $(NAME) +NAME_G3A ?= $(NAME) +G1AF := -i "$(ICON_FX)" -n "$(NAME_G1A)" --internal="$(INTERNAL)" +G3AF := -n basic:"$(NAME_G3A)" -i uns:"$(ICON_CG_UNS)" -i sel:"$(ICON_CG_SEL)" + +ifeq "$(TOOLCHAIN_FX)" "" +TOOLCHAIN_FX := sh3eb-elf +endif + +ifeq "$(TOOLCHAIN_CG)" "" +TOOLCHAIN_CG := sh4eb-elf +endif + +# fxconv flags +FXCONVFX := --fx --toolchain=$(TOOLCHAIN_FX) +FXCONVCG := --cg --toolchain=$(TOOLCHAIN_CG) + +# +# File listings +# + +NULL := +TARGET := $(subst $(NULL) $(NULL),-,$(NAME)) + +ifeq "$(TARGET_FX)" "" +TARGET_FX := $(TARGET).g1a +endif + +ifeq "$(TARGET_CG)" "" +TARGET_CG := $(TARGET).g3a +endif + +ELF_FX := build-fx/$(shell basename -s .g1a $(TARGET_FX)).elf +BIN_FX := $(ELF_FX:.elf=.bin) + +ELF_CG := build-cg/$(shell basename -s .g3a $(TARGET_CG)).elf +BIN_CG := $(ELF_CG:.elf=.bin) + +# Source files +src := $(wildcard src/*.[csS] \ + src/*/*.[csS] \ + src/*/*/*.[csS] \ + src/*/*/*/*.[csS]) +assets-fx := $(wildcard assets-fx/*/*) +assets-cg := $(wildcard assets-cg/*/*) + +# Object files +obj-fx := $(src:%=build-fx/%.o) \ + $(assets-fx:assets-fx/%=build-fx/assets/%.o) +obj-cg := $(src:%=build-cg/%.o) \ + $(assets-cg:assets-cg/%=build-cg/assets/%.o) + +# Additional dependencies +deps-fx := $(ICON_FX) +deps-cg := $(ICON_CG_UNS) $(ICON_CG_SEL) + +# All targets +all := +ifneq "$(wildcard build-fx)" "" +all += all-fx +endif +ifneq "$(wildcard build-cg)" "" +all += all-cg +endif + +# +# Build rules +# + +all: $(all) + +all-fx: $(TARGET_FX) +all-cg: $(TARGET_CG) + +$(TARGET_FX): $(obj-fx) $(deps-fx) + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -o $(ELF_FX) $(obj-fx) $(CFLAGSFX) $(LDFLAGSFX) + $(TOOLCHAIN_FX)-objcopy -O binary $(BINFLAGS) $(ELF_FX) $(BIN_FX) + fxg1a $(BIN_FX) -o $@ $(G1AF) + +$(TARGET_CG): $(obj-cg) $(deps-cg) + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -o $(ELF_CG) $(obj-cg) $(CFLAGSCG) $(LDFLAGSCG) + $(TOOLCHAIN_CG)-objcopy -O binary $(BINFLAGS) $(ELF_CG) $(BIN_CG) + mkg3a $(G3AF) $(BIN_CG) $@ + +# C sources +build-fx/%.c.o: %.c + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -c $< -o $@ $(CFLAGSFX) $(depflags) +build-cg/%.c.o: %.c + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -c $< -o $@ $(CFLAGSCG) $(depflags) + +# Assembler sources +build-fx/%.s.o: %.s + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -c $< -o $@ +build-cg/%.s.o: %.s + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -c $< -o $@ + +# Preprocessed assembler sources +build-fx/%.S.o: %.S + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -c $< -o $@ $(INCLUDE) +build-cg/%.S.o: %.S + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -c $< -o $@ $(INCLUDE) + +# Images +build-fx/assets/img/%.o: assets-fx/img/% + @ mkdir -p $(dir $@) + fxconv -i $< -o $@ $(FXCONVFX) name:img_$(basename $*) $(IMG.$*) +build-cg/assets/img/%.o: assets-cg/img/% + @ mkdir -p $(dir $@) + fxconv -i $< -o $@ $(FXCONVCG) name:img_$(basename $*) $(IMG.$*) + +# Fonts +build-fx/assets/fonts/%.o: assets-fx/fonts/% + @ mkdir -p $(dir $@) + fxconv -f $< -o $@ $(FXCONVFX) name:font_$(basename $*) $(FONT.$*) +build-cg/assets/fonts/%.o: assets-cg/fonts/% + @ mkdir -p $(dir $@) + fxconv -f $< -o $@ $(FXCONVCG) name:font_$(basename $*) $(FONT.$*) + +# Binaries +build-fx/assets/bin/%.o: assets-fx/bin/% + @ mkdir -p $(dir $@) + fxconv -b $< -o $@ $(FXCONVFX) name:bin_$(basename $*) $(BIN.$*) +build-cg/assets/bin/%.o: assets-cg/bin/% + @ mkdir -p $(dir $@) + fxconv -b $< -o $@ $(FXCONVCG) name:bin_$(basename $*) $(BIN.$*) + +# +# Cleaning and utilities +# + +# Dependency information +-include $(shell find build* -name *.d 2> /dev/null) +build-fx/%.d: ; +build-cg/%.d: ; +.PRECIOUS: build-fx build-cg build-fx/%.d build-cg/%.d %/ + +clean-fx: + @ rm -rf build-fx/ +clean-cg: + @ rm -rf build-cg/ + +distclean-fx: clean-fx + @ rm -f $(TARGET_FX) +distclean-cg: clean-cg + @ rm -f $(TARGET_CG) + +clean: clean-fx clean-cg + +distclean: distclean-fx distclean-cg + +install-fx: $(TARGET_FX) + p7 send -f $< +install-cg: $(TARGET_CG) + @ while [[ ! -h /dev/Prizm1 ]]; do sleep 0.25; done + @ while ! mount /dev/Prizm1; do sleep 0.25; done + @ rm -f /mnt/prizm/$< + @ cp $< /mnt/prizm + @ umount /dev/Prizm1 + @- eject /dev/Prizm1 + +.PHONY: all all-fx all-cg clean distclean install-fx install-cg diff --git a/assets-cg/icon-cg-sel.png b/assets-cg/icon-cg-sel.png new file mode 100644 index 0000000..7137b50 Binary files /dev/null and b/assets-cg/icon-cg-sel.png differ diff --git a/assets-cg/icon-cg-uns.png b/assets-cg/icon-cg-uns.png new file mode 100644 index 0000000..3c99f62 Binary files /dev/null and b/assets-cg/icon-cg-uns.png differ diff --git a/assets-fx/icon-fx.png b/assets-fx/icon-fx.png new file mode 100644 index 0000000..c92f12a Binary files /dev/null and b/assets-fx/icon-fx.png differ diff --git a/include/Chip8.h b/include/Chip8.h new file mode 100644 index 0000000..1d7520a --- /dev/null +++ b/include/Chip8.h @@ -0,0 +1,22 @@ +#ifndef _CHIP_8_H_ +#define _CHIP_8_H_ + +#include + +#define STACK_SIZE 0xF+1 + +struct Chip8 +{ + uint8_t memory[0xFFF+1]; + uint8_t regist[0xF+1]; + uint16_t stack[STACK_SIZE]; + uint16_t PC; //program counter + uint16_t I; //Special register + uint8_t SP; //Stack pointer + uint8_t DT; //Delay timer + uint8_t ST; //Sound timer + uint64_t vram[32];//waiting for c21 and uint128_t for big screen :3c +}; + + +#endif //_CHIP_8_H_ diff --git a/include/opcode.h b/include/opcode.h new file mode 100644 index 0000000..5d60296 --- /dev/null +++ b/include/opcode.h @@ -0,0 +1,76 @@ +#ifndef _OPCODE_H_ +#define _OPCODE_H_ + +#include +#include +#include +#include "Chip8.h" + +#define N (opcode&0x000F) +#define NNN (opcode&0x0FFF) +#define X (opcode&0x0F00)>>8 +#define Y (opcode&0x00F0)>>4 +#define KK (opcode&0x00FF) + + +void execute(); + +void op0table(); // +void op00E0(); //clear screen +void op00EE(); //return + +void op1NNN(); //jump + +void op2NNN(); //call + +void op3XKK(); //skip if reg[X] equal KK + +void op4XKK(); //skip if reg[X] not equal KK + +void op5XY0(); //skip if reg[X] equal reg[Y] + +void op6XKK(); //Load KK in reg[X] + +void op7XKK(); //reg[X] += KK, no carry + +void op8table(); +void op8XY0(); //load reg[Y] in reg [X] +void op8XY1(); //OR reg[X] and reg[Y] in reg [X] +void op8XY2(); //AND reg[X] and reg[Y] in reg [X] +void op8XY3(); //XOR reg[X] and reg[Y] in reg [X] +void op8XY4(); //add reg[X] and reg[Y] in reg[X] whit carry +void op8XY5(); //reg[X] = reg[X] -reg[Y] with NOT borrow +void op8XY6(); //rotate reg[X] -> and save the least significant bit in the carry flag +void op8XY7(); //reg[X] = reg[X] -reg[Y] with NOT borrow +void op8XYE(); //rotate reg[X] <- and save the least significant bit in the carry flag + +void op9XY0(); //skip if reg[X] not equal reg[Y] + +void opANNN(); //load NNN into I + +void opBNNN(); //jump to address regist[0]+NNN + +void opCXKK(); //set regist[X] = random(0,255) AND KK + +void opDXYN(); //xor the sprite of size 8*N at adress I on the screen at position (regist[X],regist[Y]) +//if a pixel is erased, set set carry flag. + +void opEtable(); +void opEX9E(); //skip if regist[X] equal value of key pressed +void opEXA1(); //skip if regist[X] not equal value of key pressed + +void opFtable(); +void opF5table(); +void opFX07(); //set regist[X] = DelayTimer +void opFX0A(); //set regist[X] = keycode of pressed key (wait for press if not any) +void opFX15(); //set DelayTimer = regist[X] +void opFX18(); //set SoundTimer = regist[X] +void opFX1E(); //set I = I + regist[X] +void opFX29(); //set I to the location to draw the char stored in regist[X] +void opFX33(); //store BCD representation of regist[X] in the adress I(hundreds), I+1(tens), I+2(digits) +void opFX55(); //store regist[0]~regist[X] into memory adress I~I+X +void opFX65(); //load regist[0]~regist[X] from memory adress I~I+X +void uninplemented(); + + +#endif // _OPCODE_H_ diff --git a/project.cfg b/project.cfg new file mode 100644 index 0000000..cdd7660 --- /dev/null +++ b/project.cfg @@ -0,0 +1,84 @@ +#--- +# fxSDK project configuration file for Chip8Emu +#--- + +# Project name, should be at most 8 bytes long. +# (You can also specify NAME_G1A or NAME_G3A to override individually.) +NAME := Chip8Emu + +# Internal name, should be '@' followed by at most 7 uppercase letters. +# WARNING: If this convention is not followed, the add-in might not appear in +# the main menu of the calculator! +INTERNAL := @HUITEMU + +# Output file name. The default is to take , replace spaces with dashes, +# and add .g1a (or .g3a). You can specify a different folder if you want. +TARGET_FX := +TARGET_CG := + +# fx-9860G icon location +ICON_FX = assets-fx/icon-fx.png +# fx-CG 50 icon locations +ICON_CG_UNS = assets-cg/icon-cg-uns.png +ICON_CG_SEL = assets-cg/icon-cg-sel.png + +#--- +# Toolchain selection +#--- + +# Toolchain for fx9860g. Please see also CFLAGS_FX below. +TOOLCHAIN_FX := sh-elf + +# Toolchain for fxcg50. Please see also CFLAGS_CG below. +TOOLCHAIN_CG := sh-elf + +#--- +# Compiler flags +#--- + +# Base compiler flags for the fxSDK, you usually want to keep these. +CFLAGS := -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields + +# Platform-specific compiler flags. +# <> If you are using sh3eb-elf, use -m3. (You can do this on both FX and CG.) +# <> If you are using sh4eb-elf, use -m4-nofpu. (Not ideal on FX but works.) +# <> If you are using sh4eb-nofpu-elf, then your compiler will likely use the +# FPU and cause problems on the calculator. Consider another configuration. +# <> If you are using an sh-elf with several targets, specify whichever you +# support. I recommend -m3 on FX and -m4-nofpu on CG. +# Please see also TOOLCHAIN_FX and TOOLCHAIN_CG above. +CFLAGS_FX := -D FX9860G -m3 +CFLAGS_CG := -D FXCG50 -m4-nofpu + +# Additional compiler flags, change to your own taste! +CFLAGS += -Wall -Wextra -Os + +# Include paths. Add one -I option for each folder from which you want to +# be able to include files with #include<>. +INCLUDE := -I include + +# Libraries. Add one -l option for each library you are using, and also +# suitable -L options if you have library files in custom folders. To use +# fxlib, add libfx.a to the project directory and use "-L . -lfx". +LIBS := + +# Base linker flags for the fxSDK, you usually want to keep these. +LDFLAGS_FX := -T fx9860g.ld -lgint-fx $(LIBS) -lgint-fx -lgcc +LDFLAGS_CG := -T fxcg50.ld -lgint-cg $(LIBS) -lgint-cg -lgcc + +# Additional linker flags, if you need any. +LDFLAGS := + +# Additional platform-specific linker flags. +LDFLAGS_FX += -Wl,-Map=build-fx/map +LDFLAGS_CG += -Wl,-Map=build-cg/map + +#--- +# File conversion parameters +#--- + +# Here you can add fxconv options for each converted file, individually. +# The syntax is ".". For example, to specify the parameters for a +# font name "hexa.png", you might write: +# +# FONT.hexa.png = charset:print grid:size:3x5 grid.padding:1 diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b44e7bf --- /dev/null +++ b/src/main.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include "Chip8.h" +#include "opcode.h" +struct Chip8 chip8 = { + .PC = 0x200, + .memory= { //bitmap for the fonts + 0xF0, 0x90, 0x90, 0x90, 0xF0, //0 + 0x20, 0x60, 0x20, 0x20, 0x70, //1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, //2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, //3 + 0x90, 0x90, 0xF0, 0x10, 0x10, //4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, //5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, //6 + 0xF0, 0x10, 0x20, 0x40, 0x40, //7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, //8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, //9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, //A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, //B + 0xF0, 0x80, 0x80, 0x80, 0xF0, //C + 0xE0, 0x90, 0x90, 0x90, 0xE0, //D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, //E + 0xF0, 0x80, 0xF0, 0x80, 0x80 //F + }}; + +int main(void) +{ + int file_handler; + uint16_t const * pathname = u"\\\\fls0\\PUZZLE.ch8"; + dclear(C_BLACK); + dupdate(); + file_handler = BFile_Open(pathname, BFile_ReadOnly); +/* if(file_handler > 0) + { + dtext(1,1,"reading", C_BLACK, C_WHITE); + dupdate(); + getkey(); + } + if(BFile_Read(file_handler, &chip8.memory[0x200], 3000,-1) > 0) + { + dtext(1,1,"reading", C_BLACK, C_WHITE); + dupdate(); + getkey(); + }*/ + BFile_Read(file_handler, &chip8.memory[0x200], 264,-1); + while(1) + { + execute(); + } + return 1; +} diff --git a/src/opcode.c b/src/opcode.c new file mode 100644 index 0000000..61839ac --- /dev/null +++ b/src/opcode.c @@ -0,0 +1,374 @@ +#include "Chip8.h" +#include "opcode.h" + +extern struct Chip8 chip8; + +uint16_t opcode; + +/* +Chip8 Keyboard and Casio keyboard + _________ | ___________ + |1|2|3|C| | |7|8|9|DEL| + --------- | ----------- + |4|5|6|D| | |4|5|6| x | + --------- | ----------- + |7|8|9|E| | |1|2|3| + | + --------- | ----------- + |A|0|B|F| | |0|.|E|(-)| (that's the little E for *10^) +*/ +const int Chip8Kb2Casio[0xF+1] = +{ + KEY_DOT, KEY_7, KEY_8, KEY_9, KEY_4, KEY_5, KEY_6, KEY_1, KEY_2, KEY_3, KEY_0, KEY_EXP, KEY_DEL, KEY_MUL, KEY_ADD, KEY_NEG +}; +/* +keycode are progressing from right to left and bottom to top with gap in it, so it will need a magic function to map the key we are interrested in [0x11-0x44] to [0x0-0xF] + +Casiokeycode, Casiokeycode after magic function Keyboard and Chip8 keyboard + _____________ | _________ | _________ + |41|42|43|44| | |C|D|E|F| | |1|2|3|C| + ------------- | --------- | --------- + |31|32|33|34| | |8|9|A|B| | |4|5|6|D| + ------------- | --------- | --------- + |21|22|23|24| | |4|5|6|7| | |7|8|9|E| + ------------- | --------- | --------- + |11|12|13|14| | |0|1|2|3| | |A|0|B|F| +the magic function consist to first substracting 0xC from keycode for each "tens" and then substract 0x5 + +new_kcode = old_kcode - (0xC * (old_kcode / 0x10)) - 0x5 + +care should be taken that this is only used on those 16 keys aboves + +*/ +const int CasioKb2Chip8[0xF+1] = +{ + 0xA, 0x0, 0xB, 0xF, 0x7, 0x8, 0x9, 0xE, 0x4, 0x5, 0x6, 0xD, 0x1, 0x2, 0x3, 0xC +}; + + +void (*Chip8Table[0xF+1]) ()= +{ + op0table, op1NNN, op2NNN, op3XKK, op4XKK, op5XY0, op6XKK, op7XKK, op8table, op9XY0, opANNN, opBNNN, opCXKK, opDXYN, opEtable, opFtable +}; + +void (*Chip8Table0[0xF+1]) ()= +{ + op00E0, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, op00EE, uninplemented +}; + +void (*Chip8Table8[0xF+1]) ()= +{ + op8XY0, op8XY1, op8XY2, op8XY3, op8XY4, op8XY5, op8XY6, op8XY7, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, op8XYE, uninplemented +}; + +void (*Chip8TableE[0xF+1]) ()= +{ + uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, opEX9E, opEXA1, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented +}; + + +void (*Chip8TableF[0xF+1]) ()= +{ + uninplemented, uninplemented, uninplemented, opFX33, uninplemented, opF5table, uninplemented, opFX07, opFX18, opFX29, opFX0A, uninplemented, uninplemented, uninplemented, opFX1E, uninplemented +}; + +void (*Chip8TableF5[0xF+1]) ()= +{ + uninplemented, opFX15, uninplemented, uninplemented, uninplemented, opFX55, opFX65, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented, uninplemented +}; + +void execute() +{ + char op[5]= "0000"; + char address[4]= "000"; + char addressI[]= "0000"; + char const hexa[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + opcode = (((uint16_t) chip8.memory[chip8.PC]) << 8) + (chip8.memory[chip8.PC+1]); + for(int i=0; i<4;i++) + { + op[i] =hexa[((opcode & (0xF000 >> (4*i) ))>>(4*(3-i)))] ; + addressI[i] =hexa[((chip8.I & (0xF000 >> (4*i) ))>>(4*(3-i)))] ; + } + + for(int i=0; i<3;i++) + { + address[i] =hexa[((chip8.PC & (0xF00 >> (4*i) ))>>(4*(2-i)))] ; + } + //dclear(C_WHITE); + dprint(1, 9, C_WHITE, C_BLACK, "%s", op); + dprint(1, 17, C_WHITE, C_BLACK, "%s", address); + dprint(1, 25, C_WHITE, C_BLACK, "%s", addressI); + dupdate(); + Chip8Table[(opcode&0xF000)>>12](); + //while(getkey().key != KEY_EXE) {} + chip8.PC +=2; + +} + +void op0table() +{ + Chip8Table0[opcode&0x000F](); +} + +void op00E0() //clear screen +{ + for (int i=0; i<32; i++) chip8.vram[i]=0; //clear vram + dclear(C_BLACK); //clear gint vram + dupdate(); +} + +void op00EE() //return +{ + chip8.PC=chip8.stack[chip8.SP--]; //move and decrement stak pointeur + if(chip8.SP == UINT8_MAX) //check overflow in case too much return + { + //TODO message 4 2 much return + } +} + +void op1NNN() //jump to NNN +{ + chip8.PC= NNN - 2; //PC get incremented afterward +} + +void op2NNN() //call function at NNN +{ + if(chip8.SP == STACK_SIZE - 1) //where gonna buffer overflow + { + //TODO message 4 2 much call + } + chip8.stack[++chip8.SP] = chip8.PC; //increment stack pointeur and store address on top + chip8.PC = NNN - 2; //PC get incremented afterward +} + +void op3XKK() //skip if reg[X] equal KK +{ + if(chip8.regist[X] == KK) chip8.PC += 2; +} + +void op4XKK() //skip if reg[X] not equal KK +{ + if(chip8.regist[X] != KK) chip8.PC += 2; +} + +void op5XY0() //skip if reg[X] equal reg[Y] +{ + if(chip8.regist[X] == chip8.regist[Y]) chip8.PC += 2; +} + +void op6XKK() //Load KK in reg[X] +{ + chip8.regist[X] = KK; +} + +void op7XKK() //reg[X] += KK, no carry +{ + chip8.regist[X] = chip8.regist[X] + KK; +} + +void op8table() +{ + Chip8Table8[opcode&0x000F](); +} + +void op8XY0() //load reg[Y] in reg [X] +{ + chip8.regist[X] = chip8.regist[Y]; +} + +void op8XY1() //OR reg[X] and reg[Y] in reg [X] +{ + chip8.regist[X] |= chip8.regist[Y]; +} + +void op8XY2() //AND reg[X] and reg[Y] in reg [X] +{ + chip8.regist[X] &= chip8.regist[Y]; +} + +void op8XY3() //XOR reg[X] and reg[Y] in reg [X] +{ + chip8.regist[X] ^= chip8.regist[Y]; +} + +void op8XY4() //add reg[X] and reg[Y] in reg[X] whit carry +{ + chip8.regist[0xF] = (UINT8_MAX - chip8.regist[X] < chip8.regist[Y]);//carry + chip8.regist[X] += chip8.regist[Y]; +} + +void op8XY5() //reg[X] = reg[X] -reg[Y] with NOT borrow +{ + chip8.regist[0xF] = (chip8.regist[X] > chip8.regist[Y]); + chip8.regist[X] -= chip8.regist[Y]; +} + +void op8XY6() //rotate reg[X] -> and save the least significant bit in the carry flag +{ + chip8.regist[0xF] = chip8.regist[X] & 0x1; + chip8.regist[X] >>= 1; +} + +void op8XY7() //reg[X] = reg[Y] - reg[X] with NOT borrow +{ + chip8.regist[0xF] = (chip8.regist[X] < chip8.regist[Y]); + chip8.regist[X] = chip8.regist[Y] - chip8.regist[X]; +} + +void op8XYE() //rotate reg[X] <- and save the least significant bit in the carry flag +{ + chip8.regist[0xF] = (chip8.regist[X] & 0x80) >> 7;; + chip8.regist[X] <<= 1; +} + +void op9XY0() //skip if reg[X] equal reg[Y] +{ + if(chip8.regist[X] != chip8.regist[Y]) chip8.PC += 2; +} + +void opANNN() //load NNN into I +{ + chip8.I = NNN; +} + +void opBNNN() //jump to address regist[0]+NNN +{ + chip8.PC= chip8.regist[0] + NNN - 2; //PC get incremented afterward +} + +void opCXKK() //set regist[X] = random(0,255) AND KK +{ + chip8.regist[X] = 0xFF & KK; //random 0xFF determined by a fair D6 throw... JK, TODO +} + +//xor the sprite of size 8*N at adress I on the screen at position (regist[X],regist[Y]) +//if a pixel is erased, set set carry flag. +//sprite are supposed to warp round the screen, so it will get messy +void opDXYN() +{ + uint64_t old_ram; //to save old state in order to know if pixel got erased + uint64_t new_ram; + uint64_t sprite_row; //temporary storage for the + uint8_t Xpos = chip8.regist[X]% 64; + uint8_t Ypos = chip8.regist[Y]% 32; + + chip8.regist[0xF] = 0; //reseting flag + + for (int i = 0; i> Xpos)|(sprite_row<<(64-Xpos));//move the sprite in the correct collums with wraping + old_ram = chip8.vram[(Ypos+i)%32]; + new_ram = old_ram ^ sprite_row; + chip8.regist[0xF] |= (((new_ram^old_ram)&old_ram) != 0); + chip8.vram[(Ypos+i)%32] = new_ram; + } + + // drawing routine, not optimized at all TODO + + dclear(C_BLACK); + + for(int x = 0; x < 64; x++) + { + for(int y = 0; y < 32; y++) + { + if((chip8.vram[y]>>(63-x))&0x1) drect(2*x, 2*y, 2*x+1, 2*y+1, C_WHITE); + } + } +dprint(1,33, C_WHITE, C_BLACK, "%d %d", Xpos, Ypos); + dupdate(); +} + +void opEtable() +{ + Chip8TableE[(opcode&0x00F0)>>4](); +} + +void opEX9E() //skip if regist[X] equal value of key pressed +{ + if(getkey().key == Chip8Kb2Casio[chip8.regist[X] & 0xF]) chip8.PC += 2; +} + +void opEXA1() //skip if regist[X] not equal value of key pressed +{ + if(getkey().key != Chip8Kb2Casio[chip8.regist[X] & 0xF]) chip8.PC += 2; +} + +void opFtable() +{ + Chip8TableF[opcode&0x000F](); +} + +void opF5table() +{ + Chip8TableF5[(opcode&0x00F0)>>4](); +} + +void opFX07() //set regist[X] = DelayTimer +{ + chip8.regist[X] = chip8.DT; +} + +void opFX0A() //set regist[X] = keycode of pressed key (wait for press if not any) +{ + uint kcode = getkey().key; + if(kcode % 0xF < 5 && kcode / 0x10 < 5) chip8.regist[X] = CasioKb2Chip8[kcode - (0xC * (kcode/0x10)) - 0x5]; //see .h for explanation +} + +void opFX15() //set DelayTimer = regist[X] +{ + chip8.DT = chip8.regist[X]; +} + +void opFX18() //set SoundTimer = regist[X] +{ + chip8.ST = chip8.regist[X]; +} + +void opFX1E() //set I = I + regist[X] +{ + chip8.I += chip8.regist[X]; +} + +void opFX29() //set I to the location to draw the char stored in regist[X] +{ + chip8.I = 5 * (chip8.regist[X] & 0xF);//char bitmaps are 5 bytes + //&0xF 'cause not precised what to do if regist[x] is larger than 15 +} + +void opFX33() //store BCD representation of regist[X] in the adress I(hundreds), I+1(tens), I+2(digits) +{ + chip8.memory[chip8.I + 2] = chip8.regist[X] %10; + chip8.memory[chip8.I + 1] = (chip8.regist[X] /10) % 10; + chip8.memory[chip8.I] = chip8.regist[X] / 100; +} + +void opFX55() //store regist[0]~regist[X] into memory adress I~I+X +{ + for(int i=0; i<=X;i++) chip8.memory[chip8.I+i] = chip8.regist[i]; +} + +void opFX65() //load regist[0]~regist[X] from memory adress I~I+X +{ + for(int i=0; i<=X;i++) chip8.regist[i] = chip8.memory[chip8.I+i]; +} + +void uninplemented() +{ + char op[5]= "0000"; + char address[4] = "000"; + char const hexa[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + for(int i=0; i<4;i++) + { + op[i] =hexa[((opcode & (0xF000 >> (4*i) ))>>(4*(3-i)))] ; + } + for(int i=0; i<3;i++) + { + address[i] =hexa[((chip8.PC & (0xF00 >> (4*i) ))>>(4*(2-i)))] ; + } + + dclear(C_WHITE); + dprint(1, 1, C_WHITE, C_BLACK, "%s unimplemented", op); + dprint(1, 9, C_WHITE, C_BLACK, "Position: %s", address); + dupdate(); + while(getkey().key != KEY_EXIT) {} +}