From 64917e3504c32f09a503675f3e43a362508725de Mon Sep 17 00:00:00 2001
From: Loic Guegan <loic.guegan@mailbox.org>
Date: Tue, 26 Dec 2023 09:06:40 +0100
Subject: [PATCH] Minor changes

---
 roms/games/pong_1player.ch8 | Bin 0 -> 246 bytes
 src/keypad.c                |  16 ++++-----
 src/keypad.h                |   1 -
 src/main.c                  |  33 +++++++++--------
 src/screen.c                |   1 -
 src/vcpu.c                  |  70 +++++++++++++++++++++++++++++++-----
 src/vcpu.h                  |  11 ++++++
 7 files changed, 96 insertions(+), 36 deletions(-)
 create mode 100644 roms/games/pong_1player.ch8

diff --git a/roms/games/pong_1player.ch8 b/roms/games/pong_1player.ch8
new file mode 100644
index 0000000000000000000000000000000000000000..65d63106cc088da4fc0e2cfad10e01453e724620
GIT binary patch
literal 246
zcmc~|%I3+j&*fS4>ejY9*YX&YuB0(%FeM~>5dFYzz#t@bT)dnk^Z%j`*9svj5*QyW
ztp1n40wkFd<hz+}ZR;&Kz*YOtfuWWufgwS@m+8(mkm|OU_9+SWZA^*s?Lux$LKSZI
zLQU@Sng87xG8wNG3Tb69B{Mb@G;9^>%J`Se1!P^dXB1kL$kZSTq<4YI6JYXCg2D$0
zr7L|VK$qDWGXh=r&zLcTNl2{nzvsWq|3W7!89kXY853AONR%<UIh6eq%31X3pYf;E
akD4hWsSH;_OGH0uUI}G**8l+wAOHX*Vqww%

literal 0
HcmV?d00001

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();