From c6ddcbe2bd529f2310e312559556aedbf896ec33 Mon Sep 17 00:00:00 2001 From: Loic Guegan Date: Mon, 25 Dec 2023 15:03:22 +0100 Subject: [PATCH] Minor changes --- .../1-chip8-logo.ch8} | Bin .../2-ibm-logo.ch8} | Bin roms/chip8-test-suite/3-corax+.ch8 | Bin 0 -> 697 bytes roms/chip8-test-suite/4-flags.ch8 | Bin 0 -> 1041 bytes roms/chip8-test-suite/5-quirks.ch8 | Bin 0 -> 3232 bytes roms/chip8-test-suite/6-keypad.ch8 | Bin 0 -> 913 bytes roms/chip8-test-suite/7-beep.ch8 | Bin 0 -> 110 bytes roms/chip8-test-suite/8-scrolling.ch8 | Bin 0 -> 1330 bytes roms/{logo_ibm.ch8 => ibm.ch8} | Bin src/main.c | 8 +- src/screen.c | 2 +- src/vcpu.c | 165 +++++++++++------- src/vcpu.h | 9 +- 13 files changed, 112 insertions(+), 72 deletions(-) rename roms/{logo_chip8.ch8 => chip8-test-suite/1-chip8-logo.ch8} (100%) rename roms/{logo_ibm2.ch8 => chip8-test-suite/2-ibm-logo.ch8} (100%) create mode 100644 roms/chip8-test-suite/3-corax+.ch8 create mode 100644 roms/chip8-test-suite/4-flags.ch8 create mode 100644 roms/chip8-test-suite/5-quirks.ch8 create mode 100644 roms/chip8-test-suite/6-keypad.ch8 create mode 100644 roms/chip8-test-suite/7-beep.ch8 create mode 100644 roms/chip8-test-suite/8-scrolling.ch8 rename roms/{logo_ibm.ch8 => ibm.ch8} (100%) diff --git a/roms/logo_chip8.ch8 b/roms/chip8-test-suite/1-chip8-logo.ch8 similarity index 100% rename from roms/logo_chip8.ch8 rename to roms/chip8-test-suite/1-chip8-logo.ch8 diff --git a/roms/logo_ibm2.ch8 b/roms/chip8-test-suite/2-ibm-logo.ch8 similarity index 100% rename from roms/logo_ibm2.ch8 rename to roms/chip8-test-suite/2-ibm-logo.ch8 diff --git a/roms/chip8-test-suite/3-corax+.ch8 b/roms/chip8-test-suite/3-corax+.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..317029bb4cb438471e1907d9d3785b6214ef6076 GIT binary patch literal 697 zcmY+Bzi-n(6vr)XL-C12L<7e+f*Mn;BZCyz9CIGUXjV7XI!sp z@OH)C8yAwDf{4~T>OE{lH%7PP3hXZV)*5;uj6cx)S&rEWW)Wswv_qCX@m9Tw?+_0f zVLRhqr{v!?d_TOKJ@;;w_}+j1!V8HHx1xKa4$h};2S%NS)9mG?s>6csXTtkc>ULao zn`Yr9eq{LdH0W)V+;k%z=ycpu1^t9G$ve0ZAna4%_xt8ex{)*5#xs#lvj;xo_C+5C z=i-RLvvYFW=w{@`7a||sY!IBxAN(P;g6b9E-HnoCIlnr;V`@HQjrrqXF{wM(fTw{| z#q%xvdRi^#=@^waq^D!&H9BgOx$~Fyw6@%n(8he0Z$3TkGbUZhq)N1uTDh*)meSg{ swA7ZRm8JYdBO^glpj@e?qBu#kk{DvCPE^7qHgct`fBpEVX*YlT1Jl@OkN^Mx literal 0 HcmV?d00001 diff --git a/roms/chip8-test-suite/4-flags.ch8 b/roms/chip8-test-suite/4-flags.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..431f3b081cca8fb3549e19d024289df246e8b871 GIT binary patch literal 1041 zcmaJ=zl#$=7@g!2#eimwiB|;TGJ;i*5VVm5_s*#2kHW&BV3Ca`aLHxeRKt-V3>&XI zlHgx33Y+2z5lmrm#g-|p1Hu&6A*Y@x)QjIYS&k^^!p?g;-}}BdZ(w7>B=U7E)C?FJ znZ!artCXz~GT|C!>xepKHxM(F6%Y-|ZX!OQ>=vR)*=@uoWgCc`vO9=<%I+cx%I+b) zqwGGSM;V#8kEW?lpI?N4J?VbzPP&t$)Ogqm!}sG?o?C1O#_wC9_MA+JtY^29gHz*S z{o3I4cxaL5#GO&CetwITqgH_OXHh%eIk3sotaG+IZCs~)M>YtonZ^a$Z-uR(ulb@h zG0+5;G$Gn=hwH>z@l{`y>Kv%@ORA)r6r$XY_u?<7%JZAO2cB_It}Q7q0yogV6|lle zp8$Q_j&=^K5j(PTxHDCKiK_uS2)(G6jR35fMp*R%S0_3F-MQZP4(fBxCD5jnc99Jo z!q!R9M0%_KiDt@SrW~T>th4$*4>;c$=+5?zltb3J3=Wk)9pJV#_m{eDtz5A%|48Mp z*rN{SAF2Fl)wRfg+`v43{!$O~m+VUC5cDM{0WLq5T#&2#I?kN;Gv}8wFJ|M^Mdq5y zT!X1Im|AmI|25T5x$mdkS1Grb&I>akWpc2hQYNh^<*hm1j9Vyc2Pt!JT67;ys}5=G z(Y{--wRy@c9`6-tKLNkVUyty(FoYCBdWIpT?n!CtQb=8w9(-^Kd%$4_h(x7_oO9_3 zpdJVAagz%ZNd55EDjJgd3@ literal 0 HcmV?d00001 diff --git a/roms/chip8-test-suite/5-quirks.ch8 b/roms/chip8-test-suite/5-quirks.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..5206652fb54edd895e0511c8381d3e97f599a9ab GIT binary patch literal 3232 zcmeHHZ)h9m8Gr6xSu&22Q_hy;CXOSd3@d+H&ao5RMVU^Dy*im#OsI+n-gqyS9Ff+J z9GuOAbX@Aj$yiCv@P-*qrvy55`%nf8BOmtXKwaApS}aCCY@vl?WON^fIahAT2hG~^ zoFvZ+-M;MW-XD5@&%Mw4{GLB|cBhwvbw_sP1=R;@vMURB!|Un0udk=&@F}4phed$T zdmC8Kz6@3WhG!7u;o`xHoaxx`XN37vnO%?Gmd}lVeC|qJ?#W2_#D5f$`4vI#Ss2T7 zJh~(68MrLW3h0?zP`_Q5^%q0(tC#EYQPO|h+dxL#=v~ide0t*UPu9}_wQNL80Icc0 zh?pb}MZ{CYN<6tNi* zVXgSA-TTR-*IclMgQ(kCRp``JvGbReP==kk<$S}guKyfW1>-BJA1VX0_4+*SNX zcqNkOMePsgMcD@y-VqH6ee$%|*z53a~~iD|?MQ5AR+4vhmKtdzihO z3wFBmZDg^@t|l`(jnlD;-F8+HIzQ}7a$x{CTynqlrLzt0Lv|ORvD018_2rvh*7UNs zw!BaWtMAtuMr&}%@jHxujiR%vyDQr7?(%VD1-g0?z*$1zZHmwpMcak8NLgSLEMt-P zX!|Mw9?-;!eBI{Zio9Su=O?u`JZGA#BHysJj*5H}&-t`=6i=ht?uz_ncRG(hox7iRaZhoNoud2!@vC#ii^vZ9yrWll+NHMs_QFH~v4zu7PI!C3w zjuKXkDtp2!c1Kw3^!62uA3x3-w?Fr1dn>!+5d0QD{@AlHxiG0`uhfr0@awM+&u?sc zz5>A%tTk?5e`(wOTRik{_rJGw|0=BUb`8!;hEdu7S#Q2w84CW2x6erZy}=^-eCP}P z{F@aY`g}@0_($%W@%5|0_oyP>b*&5Y{InutTrBt(<2G7?q6Yttl}Z&k4&844DrIig z`D82aWBgzE^fJwYsTb6ORVY}ds#;dav@9O73RWm&nfRbvc!oBfpkdKXlWbkL%mSLG zj<%_Dy};2`uuy}CLa16O=y(U?$aGwIsH+8wlarISs;cPX_(R5zy5-c_*j4uq zrn`MC<@U4XTx#&erQG1nf#kDl$y=0ym2Ho2ZQ6OTrS0j zVRkg7&XF;8b;3EwaLA}C%#LT?fN_k5QQDNu+$iu2k3lS-Z>P;mn-4af)v+HyxCgpk zuXntAH|bM+_a%`Q!2bA*^;hd}g`J0@(I`Oo{rf{h@!!ES@BHS@Z2<4SeZtOtw}lT5 z9z56w@TB(OeOz$*%<0h+I4OZKCfLd%fR0a_AI#6szhCIju4Rs!;Wo5$3T}IuvxVMz*?zSdZHd^)lGz5x9u7t_7w1}Q3S?Op)H^ejTK8{^;*3~{kKvR zlS)g|sg>$&g8HC-D3r9fYHkW_?}hwMk^f;MKjonwuuZ5c2)kAiq;{92|J@ zy~Ge+$tzJE^*>J_3qe;_ H2)h0WvV#A3 literal 0 HcmV?d00001 diff --git a/roms/chip8-test-suite/6-keypad.ch8 b/roms/chip8-test-suite/6-keypad.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..88250bfb537215aa54279829c7942c34d66e7674 GIT binary patch literal 913 zcmZ9IPfQa*6vk(#jkGJmFbmQsX*Rq5>7fTi4vpEv0!2}XA=oC3UIy4E1nq{9VmPRo zh#{C@!eR7a8nVURtMS0WgCTqKO5%;gI0tSfO{-u$5b8`DFU(};_s#p>yqSGkCjq>Q zqf3g7Kn+KWV8>|WcV0H~*cemxu>k=%PPS*GI1hgJ9d!%?ob}Cp?5Ib5jx#T!2|2lj(S+d)B(#%SrN|ay8X0?X->yamYaA;*8h`iPX`_) z8$}1vk)8LAJOC#}6OI5-qsWA#lDY}UBnM5Hm9$MbE;((&+mghDcO;igI3Y<*cvo`E zg!d#p6HZEgGU1eDXhKl)uh)~`51&UtO*EoeFWQQhv!Pb7Bidd`b)o;wsFY%^>i=l5 z+yB{OuYYV*7Ka{R4qhMZF5U{>9PAQ*_UjzPXm(qBI9nyP58L7|cyO~>^l>v^!fqrO z6KAoj29quJ1P@wF1doi03(R*fl>5j9+NO_Bll9`9Qmf8^EnWLUIqeGO>!Lfs+Wtl9 zQoWv+FD{*PF9Z>zLL&9Py4vWt0kmJds{IArze>0~_qeX}P;4j{F`-372re^2sVU{5 zCuB&44k@7?5theA4WjF!s^?LWBhE?LvP6*D9w*WyvbJs8!Xn}m6q#ZbQWT)P_0INc zN6$xcQ4}de`yzV_Q^PstEDSpt3&fbUk+N9Ec||~{(CHX^wg3>bH==2lwN`W1CRkXq z%4L=&n@sM~g#ybuP6iNXl})4zt5YP~(o0ssN|&w7+4hJ#IvHZapqC}s0LuWKU12F^ ufi#PA^!Xo<=TQ{^ literal 0 HcmV?d00001 diff --git a/roms/chip8-test-suite/7-beep.ch8 b/roms/chip8-test-suite/7-beep.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..27c205f7e1cb3a52c9314e8e0227aedd559bc24b GIT binary patch literal 110 zcmZ1!@*y>ev6&%-J4+^;XHm!}xsR!f(r<15An`#|N$1w~k3h1BDab&GPl(~kLLrL} z>;?=%It=d;7!qxgxEUUR)P9tBv{1+er03B*As->ELJ=_AMpElU_X#aY E02O^Dc>n+a literal 0 HcmV?d00001 diff --git a/roms/chip8-test-suite/8-scrolling.ch8 b/roms/chip8-test-suite/8-scrolling.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..eb546e74c93e8ed9513c14447911719484eed03b GIT binary patch literal 1330 zcmZvYQD|FL7{|{&NnJ_PHa*F$BP-o)E`rNyX}36~26nTi8oNxku|gmAaBgz%R_Zox zYc~6!aHCQLeHa);WXNry$&+IbLw)nYh7V(7X;p+V;UI;GLTG5+!z^CEbJBL*Y7V*o z?|$F!eE;ve;UGn9p7Q7g39cicEuz1 z8HHS!@yH?G|50!A7S5-X5)luQAT=pdJbBDtnvM@0^-C^!C0={K3ts;mW{+o2XtnK+)=Wcnnl( zDol#PmW(S0codm~DOshJ4(M&wy=ddfsf1`i`auaPleV5blyw51@RERU|;hKiv6Rx z&b+_cRqd+|S<+x!PK%x6`4&FY^3Xfd;ix>Z!5sl(+fTGb6v-^9nE2m!(2^cOmP{b3UipEFc)5I204f!0|Dct z%VXPSt^=WKL+skrb|{n_20f^vKv&1Hfq{EG6eUR7n!_kBQr=tBG$>K{g8~Up2%&+^ z#F)*e*4pkXw-Vp=$!y|GX>y`}Rx_-#sI^phZ!&2mGTBKKEPZTzDWbM^-?weV=L)uv zuu6sO)g-VJ#z!S9SpYJVO=m>d(eAs`L41z|I@@ohld}MxHC|0x6u60Gx 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/logo_chip8.ch8"); + MemLoadROM("../roms/chip8-test-suite/3-corax+.ch8"); ScreenInit(800,400); VCPUInit(); diff --git a/src/screen.c b/src/screen.c index 2744ee1..f4eb7ae 100644 --- a/src/screen.c +++ b/src/screen.c @@ -15,7 +15,7 @@ void ScreenInit(int width, int height){ SetTraceLogLevel(LOG_ERROR); // Disable anoying raylib logs InitWindow(width, height, "Chip-8 Emulator"); - SetTargetFPS(80); // Set game to run at 60 frames-per-second + SetTargetFPS(200); // Set game to run at 60 frames-per-second } void ScreenClear() { diff --git a/src/vcpu.c b/src/vcpu.c index c4187cb..c3e1e5e 100644 --- a/src/vcpu.c +++ b/src/vcpu.c @@ -26,83 +26,109 @@ void VCPUFetch(){ void VCPUDecode(){ State.X=(State.opcode>>8) & 0xF; State.Y=(State.opcode>>4) & 0xF; - State.N=State.opcode & 0xF; + State.N=State.opcode & 0x0F; + State.NN=State.opcode & 0xFF; + State.NNN=State.opcode & 0x0FFF; +} - State.NN=State.Y; - State.NN=State.NN<<4; - State.NN=State.NN | State.N; - - State.NNN=State.opcode&0x0FFF; +void VCPUDoubleDabble(unsigned char x, unsigned char *u, unsigned char *t, unsigned char *h){ + unsigned int bcd=x; + for(int i=0;i<8;i++){ + bcd=bcd<<1; + unsigned char byte=bcd & 0xFF; + unsigned char units=(bcd>>8) & 0xF; + unsigned char tens=(bcd>>12) & 0xF; + unsigned char hundreds=(bcd>>16) & 0xF; + //printf("hundreds:%04b tens:%04b units:%04b byte:%08b\n",hundreds,tens,units,byte); + if(i<7){ + if(units>4) + units+=3; + if(tens>4) + tens+=3; + if(hundreds>4) + hundreds+=3; + } + bcd = (hundreds<<16) | (tens << 12) | (units << 8) | byte; + } + *u=bcd>>8 & 0xF; + *t=bcd>>12 & 0xF; + *h=bcd>>16 & 0xF; } void VCPUExecute(){ - // VCPUDump(); + VCPUDump(); switch(State.opcode >> 12){ case 0x0: // Clear screen or return from subroutine - if(State.N == 0){ // Clear screen + if(State.N == 0x0){ // Clear screen ScreenClear(); } - else { // Return from subroutine + else if(State.N == 0xE) { // Return from subroutine State.PC=State.stack[State.S]; State.S--; } - break - ;; + break; + case 0x1: // Jump State.PC=State.NNN; - break - ;; + break; + case 0x2: // Call State.S++; State.stack[State.S]=State.PC; State.PC=State.NNN; - break - ;; + break; + case 0x3: // SE: VX, byte if(State.V[State.X]==State.NN) State.PC+=2; break; - ;; + case 0x4: // SNE: VX, byte if(State.V[State.X]!=State.NN) State.PC+=2; break; - ;; + case 0x5: // SE: VX, VY - if(State.V[State.X]==State.V[State.Y]) - State.PC+=2; + if(State.N == 0){ + if(State.V[State.X]==State.V[State.Y]) + State.PC+=2; + } break; - ;; + case 0x6: State.V[State.X]=State.NN; - break - ;; + break; + case 0x7: - State.V[State.X]+=State.NN; - break - ;; + State.V[State.X]=State.V[State.X] + State.NN; + break; + case 0x8: // Register operations switch(State.N){ + case 0x0: // VX = VY + State.V[State.X]=State.V[State.Y]; + break; + case 0x1: // VX = VX OR VY State.V[State.X]=State.V[State.X] | State.V[State.Y]; break; - ;; + case 0x2: // VX = VX AND VY State.V[State.X]=State.V[State.X] & State.V[State.Y]; break; - ;; + case 0x3: // VX = VX XOR VY State.V[State.X]=State.V[State.X] ^ State.V[State.Y]; break; - ;; + case 0x4: // VX = VX + VY - if(State.V[State.X] + State.V[State.Y] > 255) + if((State.V[State.X] + State.V[State.Y]) > 255) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; - State.V[State.X]=(State.V[State.X] + State.V[State.Y]) & 0xFF; + State.V[State.X]=State.V[State.X] + State.V[State.Y]; break; - ;; + case 0x5: // VX = VX - VY if(State.V[State.X] > State.V[State.Y]) State.V[REG_FLAG]=1; @@ -110,7 +136,7 @@ void VCPUExecute(){ State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] - State.V[State.Y]; break; - ;; + case 0x6: // VX = VX SHR 1 if(State.V[State.X] & 0x1 == 1) State.V[REG_FLAG]=1; @@ -118,55 +144,57 @@ void VCPUExecute(){ State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] >> 1; break; - ;; + case 0x7: // VX = VY - VX - if(State.V[State.X] < State.V[State.Y]) + if(State.V[State.Y] > State.V[State.X]) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.Y] - State.V[State.X]; break; - ;; + case 0xE: // VX = VX SHL 1 - if(State.V[State.X] >> 15 == 1) + if(State.V[State.X] >> 7 == 1) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] << 1; break; - ;; + } - break - ;; - case 0x9: // SNE: VX, VY - if(State.V[State.X]!=State.V[State.Y]) - State.PC+=2; break; - ;; + + case 0x9: // SNE: VX, VY + if(State.N==0){ + if(State.V[State.X]!=State.V[State.Y]) + State.PC+=2; + } + break; + case 0xA: State.I=State.NNN; - break - ;; + break; + case 0xB: State.PC=State.V[0]+State.NNN; - break - ;; + break; + case 0xC: unsigned short n = rand() % 255 + 1; State.V[State.X]=n & State.NN; - break - ;; + break; + case 0xD: // Draw a sprite - int X=State.V[State.X]%63; - int Y=State.V[State.Y]%31; + int X=State.V[State.X]&63; + int Y=State.V[State.Y]&31; State.V[REG_FLAG]=0; // Set flag to 0 - int width,height; + int width, height; ScreenWH(&width,&height); for(char row=0;row=height) break; - char sprite; + unsigned char sprite; MemRead(&sprite,1,State.I+row); // Load sprite // Draw sprite for(int shift=0;shift<8;shift++){ @@ -178,51 +206,56 @@ void VCPUExecute(){ } } break; - ;; + case 0xE: // TODO - break;; + break; + case 0xF: switch(State.NN){ case 0x07: // Get timer State.V[State.X]=State.DT; break; - ;; + case 0x0A: // TODO break; - ;; + case 0x15: // Set timer State.DT=State.V[State.X]; break; - ;; + case 0x18: // Set sound timer State.ST=State.V[State.X]; break; - ;; + case 0x1E: // I = I + VX State.I=State.I+State.V[State.X]; break; - ;; + case 0x29: // TODO break; - ;; + case 0x33: - // TODO + unsigned char units, tens, hundreds; + VCPUDoubleDabble(State.V[State.X],&units,&tens,&hundreds); + MemCopy(&hundreds,1,State.I); + MemCopy(&tens,1,State.I+1); + MemCopy(&units,1,State.I+2); + // printf("hundreds:%d tens:%d units:%d byte:%d\n",hundreds,tens,units,State.V[State.X]); break; - ;; + case 0x55: MemCopy(State.V,0xF,State.I); break; - ;; + case 0x65: MemRead(State.V,0xF,State.I); break; - ;; + } break; - ;; } } diff --git a/src/vcpu.h b/src/vcpu.h index dbcba0a..fccd397 100644 --- a/src/vcpu.h +++ b/src/vcpu.h @@ -25,10 +25,10 @@ typedef struct VCPU_State { // Intruction (opcode + decoded fields) unsigned short opcode; - char X; - char Y; - char N; - char NN; + unsigned char X; + unsigned char Y; + unsigned char N; + unsigned char NN; unsigned short NNN; } VCPU_State; @@ -36,4 +36,5 @@ void VCPUInit(); void VCPUFetch(); void VCPUDecode(); void VCPUExecute(); +void VCPUDoubleDabble(unsigned char x, unsigned char *u, unsigned char *t, unsigned char *h); void VCPUDump();