summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--roms/games/pong_1player.ch8bin0 -> 246 bytes
-rw-r--r--src/keypad.c16
-rw-r--r--src/keypad.h1
-rw-r--r--src/main.c33
-rw-r--r--src/screen.c1
-rw-r--r--src/vcpu.c70
-rw-r--r--src/vcpu.h11
7 files changed, 96 insertions, 36 deletions
diff --git a/roms/games/pong_1player.ch8 b/roms/games/pong_1player.ch8
new file mode 100644
index 0000000..65d6310
--- /dev/null
+++ b/roms/games/pong_1player.ch8
Binary files differ
diff --git a/src/keypad.c b/src/keypad.c
index d106642..f26c5e2 100644
--- a/src/keypad.c
+++ b/src/keypad.c
@@ -19,21 +19,19 @@ int map[]={
KEY_V // F
};
-int KeypadIsPressed(unsigned char c){
- if(c<=0xF){
- if(IsKeyPressed(map[c]))
- return 1;
+int KeypadKeycodeValid(int keycode){
+ for(int i=0;i<16;i++){
+ if(map[i]==keycode)
+ return i;
}
- return 0;
+ return -1;
}
+
int KeypadGetPressed(){
int keycode=GetKeyPressed();
if(keycode){
- for(int i=0;i<16;i++){
- if(map[i]==keycode)
- return 1;
- }
+ return KeypadKeycodeValid(keycode);
}
return -1;
}
diff --git a/src/keypad.h b/src/keypad.h
index 9339280..922d2a8 100644
--- a/src/keypad.h
+++ b/src/keypad.h
@@ -2,6 +2,5 @@
#include "raylib.h"
-int KeypadIsPressed(unsigned char c);
int KeypadGetPressed();
diff --git a/src/main.c b/src/main.c
index 7591627..ea8d606 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,34 +1,33 @@
#include "screen.h"
#include "mem.h"
#include "vcpu.h"
-
#include <stdio.h>
+
+#define ROM "../roms/chip8-test-suite/6-keypad.ch8"
+//#define ROM "../roms/games/pong_1player.ch8"
+
int main(int argc, char *argv[])
{
- /* unsigned char byte=137; */
- /* unsigned char u,t,h; */
- /* VCPUDoubleDabble(byte,&u,&t,&h); */
- /* printf("%d: %01d%01d%01d\n",byte,h,t,u); */
- /* return 0; */
// Initialize
MemInit();
- MemLoadROM("../roms/games/paddles.ch8");
-
+ MemLoadROM(ROM);
ScreenInit(800,400);
VCPUInit();
- // MemDump();
- int i=0;
+ // Set game to run at very high FPS (prevent raylib to interfer with emulator FPS)
+ SetTargetFPS(VCPU_FREQ*100);
+
+ // Emulator main loop
+ int i=0;
while (!WindowShouldClose()){
- for(int i=0;i<30;i++){
- VCPUFetch();
- VCPUDecode();
- VCPUExecute();
- }
- ScreenUpdate();
+ VCPUTick();
+ if(i%600 == 0)
+ printf("tick\n");
+ i++;
}
-
+
+ // Close screen
ScreenClose();
return 0;
diff --git a/src/screen.c b/src/screen.c
index 2e77ba9..a445bd8 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -15,7 +15,6 @@ void ScreenInit(int width, int height){
SetTraceLogLevel(LOG_ERROR); // Disable anoying raylib logs
InitWindow(width, height, "Chip-8 Emulator");
- SetTargetFPS(60); // Set game to run at 60 frames-per-second
}
void ScreenClear() {
diff --git a/src/vcpu.c b/src/vcpu.c
index 67dea13..1f36b68 100644
--- a/src/vcpu.c
+++ b/src/vcpu.c
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <time.h>
// Current VCPU state
@@ -13,6 +14,9 @@ VCPU_State State;
void VCPUInit(){
State.PC=ADDR_ROM;
State.S=0;
+ State.dtst_ticks=0;
+ State.screen_ticks=0;
+ State.keypress=-1;
srand(time(NULL));
}
@@ -204,11 +208,20 @@ void VCPUExecute(){
case 0xE:
if(State.NN==0x9E){ // Skip if keypress in VX
- if(KeypadIsPressed(State.V[State.X]&0x0F)){
- State.PC+=2;
+ if(State.keypress >= 0){
+ if(State.V[State.X]&0x0F == State.keypress&0xF){
+ State.PC+=2;
+ }
+ State.keypress=-1;
}
}else if(State.NN==0xA1){ // Skip if not keypress in VX
- if(!KeypadIsPressed(State.V[State.X]&0x0F))
+ if(State.keypress >=0){
+ if(State.V[State.X]&0x0F != State.keypress&0xF){
+ State.PC+=2;
+ }
+ State.keypress=-1;
+ }
+ else
State.PC+=2;
}
break;
@@ -220,13 +233,15 @@ void VCPUExecute(){
break;
case 0x0A:
- int key=KeypadGetPressed();
- if(key >= 0){
- State.V[State.X]=key&0x0F;
+ if(State.keypress >=0){
+ State.V[State.X]=State.keypress&0xF;
+ if(State.V[State.X]&0x0F != State.keypress&0xF){
+ State.PC+=2;
+ State.keypress=-1;
+ }
}
else
- State.PC-=2; // Go back to last instruction (loop until key is pressed)
-
+ State.PC-=2; // Go back to last instruction (loop until key is pressed)
break;
case 0x15: // Set timer
@@ -267,6 +282,45 @@ void VCPUExecute(){
}
}
+void VCPUTick(){
+ struct timespec start, stop;
+ double duration, delay;
+
+ // Run and benchmark CPU pipeline
+ clock_gettime(CLOCK_REALTIME, &start);
+ VCPUFetch();
+ VCPUDecode();
+ VCPUExecute();
+ State.dtst_ticks++;
+ State.screen_ticks++;
+ clock_gettime(CLOCK_REALTIME, &stop);
+
+ // Adjust pipeline duration
+ duration=(stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec)*1e-9;
+ delay=1.0/VCPU_FREQ-duration;
+ if(delay>0){
+ usleep(delay*1e6);
+ }
+
+ // Update Delay Timer and Sound Timer
+ if(State.dtst_ticks>=(1.0*VCPU_FREQ/DTST_FREQ)){
+ State.dtst_ticks=0;
+ if(State.DT>0)
+ State.DT--;
+ }
+
+ // Refresh screen
+ if(State.screen_ticks>=(1.0*VCPU_FREQ/SCREEN_FREQ)){
+ State.screen_ticks=0;
+ ScreenUpdate();
+ }
+
+ // Update keypressed
+ int keypress=KeypadGetPressed();
+ if(keypress>=0)
+ State.keypress=keypress;
+}
+
void VCPUDump(){
printf("opcode: 0x%04x\n",State.opcode&0xFFFF);
printf("X: 0x%01x\n",State.X);
diff --git a/src/vcpu.h b/src/vcpu.h
index fccd397..3da6b37 100644
--- a/src/vcpu.h
+++ b/src/vcpu.h
@@ -1,5 +1,8 @@
#pragma once
+#define VCPU_FREQ 600
+#define DTST_FREQ 60
+#define SCREEN_FREQ 60
#define REG_FLAG 0xF
typedef struct VCPU_State {
@@ -30,11 +33,19 @@ typedef struct VCPU_State {
unsigned char N;
unsigned char NN;
unsigned short NNN;
+
+ // Keypressed
+ int keypress;
+
+ // Count VCPU ticks
+ int dtst_ticks;
+ int screen_ticks;
} VCPU_State;
void VCPUInit();
void VCPUFetch();
void VCPUDecode();
void VCPUExecute();
+void VCPUTick();
void VCPUDoubleDabble(unsigned char x, unsigned char *u, unsigned char *t, unsigned char *h);
void VCPUDump();