// JSE-Chip8 // by Dan // Created 2024/12/12 //play it here: https://agameaweek.com/JSE/ or https://gotojse.com/index.html Graphics 470,200,1 Dim V(16) Dim Keys(16) Dim Display(64*32) Dim Stack(16) Dim KeyNr(16) AnyKeyPressed=0 //dim Spri$(17) MenuMaxBTN=10 Dim MenuB(MenuMaxBTN,4) Dim MenuTxt$(MenuMaxBTN) Gosub DefineMenu speed=5 Chip8version=1 //1 - Chip 8 Everything else fixes some quirks Chip9Fix=0 //1 some games like hidden and blinky are playable when this is 1 and Chip8Version=0 FontStartAddress = 0 SizeX=6 SizeY=6 KeyNr(1)=49 //1 KeyNr(2)=50 //2 KeyNr(3)=51 //3 KeyNr(4)=81 //q KeyNr(5)=87 //w KeyNr(6)=69 //e KeyNr(7)=65 //a KeyNr(8)=83 //s KeyNr(9)=68 //d KeyNr(10)=89 //y KeyNr(0)=88 //x KeyNr(11)=67 //c KeyNr(12)=52 //4 KeyNr(13)=82 //r KeyNr(14)=70 //f KeyNr(15)=86 //v needRedraw = False TotalMemory=4096 Dim Mem(TotalMemory) RomChoice = -1 GOSUB AddTestRom Gosub AddDefaultFont clrmem=0 Gosub init TimerSpeed=MilliSec() SND=1 Go=1 DBG=0 DebugMode Off pccount=0 oldinstr$="" Repeat SetColor #000000 Rect 395,0,ScreenWidth()-395,ScreenHeight() SetColor#FFFFFF TMPC$=MenuTxt$(MM) If TMPC$=="Start" then go=(go+1) mod 2 wait 0.25 Endif If TMPC$=="Chip8" then Chip8Version=(chip8version+1) mod 2 wait 0.25 Endif If TMPC$=="Chip9" then Chip9Fix=(Chip9Fix+1) mod 2 wait 0.25 Endif If TMPC$=="Mute" then SND=(SND+1) mod 2 wait 0.25 Endif If TMPC$=="D+" then Speed=(Speed + (speed<10)) wait 0.25 Endif If TMPC$=="D-" then Speed=(Speed - (speed>0)) wait 0.25 Endif If TMPC$=="Restart" clrmem=0 Gosub init Wait0.50 TimerSpeed=MilliSec() Go=1 EndIf If TMPC$=="Reboot" then clrmem=1 Gosub init GOSUB AddTestRom Gosub AddDefaultFont TimerSpeed=MilliSec() Go=1 Wait 0.5 EndIf If needRedraw == True then Gosub DrawScreen EndIf MoB=MouseDown() Gosub MenuButtons Text 444,14,Go Text 444,34,Chip8version Text 444,93,Chip9Fix Text 400,108,cycle Text 444,54,SND Text 424,74,Speed If go==1 then if millisecs()-TimerSpeed > Speed then for sxxx=0 to (10)-speed oldpc=pc oldinstr$=instruction$ Gosub Chip8Run if pc==oldpc then //detect infinite loop and stop it If oldinstr$=="1000" or oldinstr=="B000" then pccount=pccount+1 if pccount>2 then go=0 pccount=0 EndIf Else pccount=0 EndIf Next TimerSpeed=MilliSec() EndIf Else If KeyHit() then Gosub Chip8Run EndIf Flip Forever //*****************************************************************Main Loop END END //tempx=0 //Gosub DISPLAYSTATS //If KeyHit() then Gosub Chip8Run //tempx=120 //Gosub DISPLAYSTATS .DISPLAYSTATS For x=0 to 15 : Text 460+tempx,10+(x*13),Hex$(V(X),2) : next Text 460+TempX,229,"Cy="+Cycle Text 460+TempX,243,"Pc="+Hex$(PC,3) Text 460+TempX,257,"I="+hex$(I,3) RETURN End .Chip8Run //Local opcode , instruction, address, Vx, Vy, value , byte, carry opcode=(Mem(Pc) Shl 8) + Mem(Pc+1) instruction$=Upper$(Hex$(opcode & HexToInt("F000"))) address= opcode & 4095 Vx=(opcode & 3840) Shr 8 Vy=(opcode & 240) Shr 4 byte = opcode & 255 value = opcode & 15 //Print Hex$(opcode,4) //print Hex$(instruction,4) //Print Hex$(address,3) //print Hex$(Vx,1) //print Hex$(Vy,1) //print Hex$(byte,2) //Print Hex$(value,1) carry=0 cycle=cycle+1 Gosub GetTheKeys if DBG>0 then Notify( Cycle+": "+Hex$(Opcode,4)+" "+Instruction$+" "+Hex(Address,3)+" "+Hex$(Vx,1)+" "+Hex$(Vy,1)+" "+Hex$(Byte,2)+" "+Hex$(value,1)+" V ("+Vx+")="+V(Vx)+" V ("+Vy+")="+V(Vy),210,0) If Instruction$=="0" If DBG>1 then Notify ("Instruction Set 0000",200,0) If byte==HexToInt("E0")then Gosub ClearDisplay Pc=Pc+2 NeedRedraw=True If DBG>1 then Notify ("Clearing Screen",200,0) EndIf If Byte==HexToInt("EE") then StackPointer=StackPointer-1 If StackPointer => 0 or StackPointer<=15 Then PC=Stack(StackPointer)+2 If DBG>1 then Notify ("Return From SUB",200,0) Else go=0 If DBG>1 then Notify ("Stack Is out of bounds",200,0) EndIf EndIf EndIf If Instruction$=="1000" Then //1NNN Jumps to address NNN Pc=address If DBG>1 then Notify ("Jumping to "+pc,200,0) EndIf If Instruction$=="2000" Then //2NNN Call Subroutine at NNN If StackPointer<16 then Stack(StackPointer) = Pc StackPointer=StackPointer+1 Pc=address If DBG>1 then Notify ("Sub to "+pc,200,0) Else go=0 If DBG>1 then Notify ("Stack Overflow",200,0) EndIf EndIf If Instruction$=="3000" Then Pc=Pc+2+((V(Vx) == byte)*2) If DBG>1 then Notify ( "3000 Skip if Vx "+V(vX)+" = " + byte,200,0) EndIf If Instruction$=="4000" Then Pc=Pc+2+((V(Vx)<>byte)*2) If DBG>1 then Notify ( "Skip if Vx "+V(vX)+" <> " + byte,200,0) EndIf If Instruction$=="5000" Then Pc=Pc+2+((V(Vx) == V(Vy))*2) If DBG>1 then Notify ( "Skip if Vx (" + Hex$(V(Vx),2)+ ") <> V (" + Hex$(V(Vy),2)+")",200,0) EndIf If Instruction$=="6000" Then V(Vx)=Byte Pc=Pc+2 If DBG>1 then Notify ( "V (" + Vx+ ") is Set to " + Hex$(byte),200,0) EndIf If Instruction$=="7000" Then V(Vx)=(V(Vx)+byte) & 255 Pc=Pc+2 If DBG>1 then Notify ( "V (" + Vx+ ") is Set to Vx + " + Hex$(byte) +" = "+V(Vx),200,0) EndIf If Instruction$=="8000" Then If Value==HexToInt("0") then // ;8XY0 V(Vx) = V(Vy) Pc=Pc+2 If DBG>1 then Notify ( "8XY0" ,200,0) EndIf If Value==HexToInt("1") then // ;8XY1 V(Vx)= (V(Vx) | V(Vy)) & 255 If Chip8version==1 Then V(15)=0 //Fixing a Chip8 quirk Pc=Pc+2 If DBG>1 then Notify ( "8XY1" ,200,0) EndIf If Value==HexToInt("2") then // ;8XY2 V(Vx)=(V(Vx) & V(Vy)) If Chip8version==1 Then V(15)=0 // Fixing a Chip8 quirk Pc=Pc+2 If DBG>1 then Notify ( "8XY2" ,200,0) EndIf If Value==HexToInt("3") then // ;8XY3 V(Vx)=((V(Vx) | V(Vy)) - (V(Vx) & V(Vy))) & 255 If Chip8version==1 Then V(15)=0 // Fixing a Chip8 quirk Pc=Pc+2 If DBG>1 then Notify ( "8XY3" ,200,0) EndIf If Value==HexToInt("4") then // ;8XY4 carry=((V(Vx)+V(Vy)) > 255) V(Vx)=(V(Vx)+V(Vy)) & 255 V(15)=carry Pc=Pc+2 If DBG>1 then Notify ( "8XY4" ,200,0) EndIf If Value==HexToInt("5") then // ;8XY5 carry= (V(Vx)=>V(Vy)) V(Vx) =((V(Vx)-V(Vy)) & 255) V(15)=carry Pc=Pc+2 If DBG>1 then Notify ( "8XY5" ,200,0) EndIf If Value==HexToInt("6") then // ;8XY6 If Chip8version==1 Then carry=(V(Vy) & 1) V(Vx) = V(Vy) Shr 1 Else carry=(V(Vx) & 1) V(Vx) = V(Vx) Shr 1 EndIf V(15) = carry Pc = Pc+2 If DBG>1 then Notify ( "8XY6" ,200,0) EndIf If Value==HexToInt("7") then // ;8XY7 carry=(V(Vy)=>V(Vx)) V(Vx) = (V(Vy)-V(Vx)) & 255 V(15)=carry Pc=Pc+2 If DBG>1 then Notify ( "8XY7" ,200,0) EndIf If Value==HexToInt("E") then // ;8XYE If Chip8version==1 Then carry = ((V(Vy) & 128)>0) V(Vx) = (V(Vy) Shl 1) & 255 Else carry = ((V(Vx) & 128)>0) V(Vx) = (V(Vx) Shl 1) & 255 EndIf V(15) = carry Pc=Pc+2 If DBG>1 then Notify ( "8XYE" ,200,0) EndIf EndIf If Instruction$=="9000" Then result=pc Pc=Pc+2+((V(Vx)<>V(Vy))*2) Debug " Vx="+V(Vx)+" Vy="+V(Vy)+" Pc="+result+" PcN:"+pc If DBG>1 then Notify ( "9000 Skip if Vx <> Vy "+V(Vx)+" <> "+V(Vy)+" OldPc="+result+" NewPc="+pc,200,0) EndIf If Instruction$=="A000" Then I=address Pc=Pc+2 If DBG>1 then Notify ( "I= " + Hex$(address,3),200,0) EndIf If Instruction$=="B000" Then Pc= address + V(0) If DBG>1 then Notify ( "B000 jump to V0 =" + V(0),200,0) EndIf If Instruction$=="C000" Then V(Vx)=(Rand(0,255) & byte) Pc=Pc+2 If DBG>1 then Notify ( "C000 Vx = random and byte " + V(Vx),200,0) EndIf If Instruction$=="D000" Then height=value V(15) = 0 // Set the collision flag to 0 //spri$(0) = height For y=0 To height - 1 ln=mem(I + y) //spri$(y + 1) = "" For x = 1 To 8 Pixel=(ln & (256 Shr x)) // tmp = "." // If pixel <> 0 Then tmp = "#" // spri$(y + 1) = spri$(y + 1) + tmp If Pixel>0 Then tx= V(Vx) Mod 64 ty= V(Vy) Mod 32 tx=tx + (x-1) ty=ty + y If tx<64 And ty<32 Then id= (ty * 64) + tx If Display(id) == 1 Then V(15) = 1 // Collision happened Display(ID) = (Display(ID) | 1)-(Display(Id) & 1) EndIf EndIf Next Next needRedraw = True Pc = Pc +2 If DBG>1 then Notify ( "Draw to Screen",200,0) EndIf If Instruction$=="E000" Then If byte==HexToInt("9E") Pc=Pc+2+((Keys(V(Vx)) > 0)*2) If DBG>1 then Notify ( "Ex9E Skip if key pressed"+(Keys(V(Vx)) > 0),200,0) EndIf If byte==HexToInt("A1") Pc=Pc+2+((Keys(V(Vx)) == 0)*2) If DBG>1 then Notify ( "ExA1 Skip if key not pressed"+(Keys(V(Vx)) == 0),200,0) EndIf EndIf If Instruction$=="F000" Then If DBG>1 then Notify ( "Byte= " + Hex$(byte),200,0) If Byte==HexToInt("07") then // ;FX07 V(Vx)=DelayTimer Pc=Pc+2 If DBG>1 then Notify ( "FX07 Key Pressed" ,200,0) EndIf If Byte==HexToInt("0A") then // ;FX0A If AnyKeyPressed==0 Then x=0 .recheck If Keys(x) == 1 Then //wait for a keypress AnyKeyPressed=x //and store it Goto recheckexit EndIf x=x+1 if x==16 then goto recheckexit Goto recheck .recheckexit Else If Keys(AnyKeyPressed)==0 Then V(Vx) = AnyKeyPressed AnyKeyPressed=0 Pc=Pc+2 //The key has been released, skip EndIf EndIf If DBG>1 then Notify ( "FX0A Key Pressed and Released" ,200,0) EndIf If Byte==HexToInt("15") then // ;FX15 DelayTimer=V(Vx) Dtimer=MilliSecs() Pc=Pc+2 If DBG>1 then Notify ( "FX15 DelayTimer="+V(Vx) ,200,0) EndIf If Byte==HexToInt("18") then // ;FX18 SoundTimer= V(Vx) Stimer=MilliSecs() Pc=Pc+2 If DBG>1 then Notify ( "FX18 Soundtimer="+V(Vx) ,200,0) EndIf If Byte==HexToInt("1E") then // ;FX1E Set I to VX carry= (I + V(Vx)) > 4095 I = (I + V(Vx)) & 4095 V(15)=carry Pc=Pc+2 If DBG>1 then Notify ( "Filled V0 to Vx from memory " ,200,0) EndIf If Byte==HexToInt("29") then // ;FX29 I = FontStartAddress+(V(Vx)*5) Pc=Pc+2 If DBG>1 then Notify ( "FX29" ,200,0) EndIf If Byte==HexToInt("33") then // ;FX33 B100=Floor(V(Vx)/100) B10=Floor((V(Vx)/10) % 10) B1=Floor((V(Vx) Mod 100) % 10) Mem(I)=B100 Mem(I+1)=B10 Mem(I+2)=B1 Pc=Pc+2 If DBG>1 then Notify ( "FX33 Vx ("+V(Vx)+" ) stored as I="+B100+" I+1="+B10+" I+2="+B1 ,200,0) EndIf If Byte==HexToInt("55") then // ;FX55 Fills V0 To Vx with values from I For t=0 To Vx Mem(I + t)= V(t) Next if Chip9Fix==0 then I=I+Vx+1 Pc=Pc+2 If DBG>1 then Notify ( "Filled V0 to Vx from memory " ,200,0) EndIf If Byte==HexToInt("65") then // ;FX65 Fills V0 To Vx with values from I For t=0 To Vx V(t)=Mem(I + t) Next if Chip9Fix==0 then I=I+Vx+1 Pc=Pc+2 If DBG>1 then Notify ( "Filled V0 to Vx from memory " ,200,0) EndIf EndIf If SoundTimer>0 Then If MilliSecs()-Stimer>(15+(speed)) Then SoundTimer=SoundTimer-1 Stimer=MilliSecs() EndIf If snd==1 Then PlaySFX("Beep_4",0.30,0.01) EndIf If DelayTimer>0 Then If MilliSecs()-Dtimer>(15+(speed)) Then DelayTimer=DelayTimer-1 Dtimer=MilliSecs() EndIf EndIf Return END .AddDefaultFont PokeStart=FontStartAddress Error$="" Pok$="F0909090F02060202070F010F080F0F010F010F09090F01010F080F010F0F080F090F0F010204040" Gosub PokeStringToArray Pok$="F090F090F0F090F010F0F090F09090E090E090E0F0808080F0E0909090E0F080F080F0F080F08080" Gosub PokeStringToArray Return .AddTestRom PokeStart=512 Error$="" Romname$="BuiltIn Rom" cls RomChoice=RomChoice+1 If RomChoice>7 then RomChoice=0 If RomChoice==0 then Goto Rom0 If RomChoice==1 then Goto Rom1 If RomChoice==2 then Goto Rom2 If RomChoice==3 then Goto Rom3 If RomChoice==4 then Goto Rom4 If RomChoice==5 then Goto Rom5 If RomChoice==6 then Goto Rom6 If RomChoice==7 then Goto Rom7 Goto RomExit .Rom0 // Tetris (FranDachille1991) Pok$="A2B423E622B67001D0113025120671FFD011601AD01160253100120EC4704470121CC303601E6103225CF515D0143F01123CD01471FFD0142340121CE7A12272E8A12284E9A12296E29E12" Pok$=Pok$+"506600F615F6073600123CD0147101122AA2C4F41E660043016604430266084303660CF61E00EED01470FF23343F0100EED0147001233400EED014700123343F0100EED01470FF233400EE" Pok$=Pok$+"D014730143046300225C23343F0100EED01473FF43FF6303225C233400EE8000670568066904611F6510620700EE40E0000040C0400000E04000406040004040600020E00000C040400000" Pok$=Pok$+"E080004040C00000E020006040400080E0000040C08000C060000040C08000C060000080C040000060C00080C040000060C000C0C00000C0C00000C0C00000C0C000004040404000F00000" Pok$=Pok$+"4040404000F00000D014663576FF3600133800EEA2B48C103C1E7C013C1E7C013C1E7C01235E4B0A237291C000EE71011350601B6B00D0113F007B01D01170013025136200EE601BD01170" Pok$=Pok$+"01302513748E108DE07EFF601B6B00D0E13F001390D0E11394D0D17B017001302513864B0013A67DFF7EFF3D01138223C03F0123C07A0123C080A06D0780D2400475FE4502650400EEA700" Pok$=Pok$+"F255A804FA33F265F0296D326E00DDE57D05F129DDE57D05F229DDE5A700F265A2B400EE6A00601900EE3723" Gosub PokeStringToArray Goto RomExit .Rom1 // Maze (David Winter) Pok$="60006100A222C2013201A21ED0147004304012046000710431201204121C8040201020408010" Gosub PokeStringToArray Goto RomExit .Rom2 // Bowling (Gooitzen van der Wal).ch8 Pok$="63146400255E600525B4630C25BC690689B53B004F00120CFB29D6458DB07D096314640C257A600525B4630C25BC690989B54F00122CFB29D3453B0012466B0A6307600125B480B0A6A6F0" Pok$=Pok$+"556E0063146418600525B4A64A25B6600E25B425B4600D25B4630C25BC690389B53B004F001266FB29D34560004B0260044B016008A4A9F05525DEA69460006100F05571013112128C6C0A" Pok$=Pok$+"7E0126086A00237663006410255E25C680C025B46302641B257A25C680E0259663306400A67CD3497308D349A696FC1EF0656401300112EA6339A66FD347A6A7F0656332640225B412F463" Pok$=Pok$+"3A6402FB29D34512D4400012E06331A675D34725DE9CD012FE7C01129800E063006400257A25C680E0300E131225B4131425966C0A6300740980C025B425C6A68AFC1EF0658500A690FC1E" Pok$=Pok$+"F065259825F49CD013447C01692489353F0113166325131A633764004E0E134AA6A6F0659E00135A2596F90A1294F90A6E0E6C0A26084000136E6A0040016A0123769CD012FE7C01136025" Pok$=Pok$+"DE00E0A68462006100D121710831401380721F421F137EA68561006201D12F6210D12FA6476127620ED124612D620A2590D1246133620625902590D12461396202259025902590D1246B00" Pok$=Pok$+"A6426101620E631A6401D125682269026501E5A114106502E5A114146503E5A114186505E5A1141C6507E5A114226508E5A114206509E5A1141ED12592301406824413CC340113C8630164" Pok$=Pok$+"FF13CC79FC142279FC142079FC141E79FE7809780925EE248EA690FC1EF0658800A696FC1EF06589003A001466490314583900145C26264B0A14842614A6A780B0F0557A013B0A13C0139A" Pok$=Pok$+"262679FF262679FF3E0E144214484901147A2626A6A7F06580B4400A148625DE1488262679FF3E0E146A147679017901261400E000EE63006F003F0014AED1255180149E83907103823441" Pok$=Pok$+"3D00EED125600025E01492D12566276702642A84153F0014F8643084153F0014CE643684153F0014F6760C760642001514640584253F001522640D84253F00151E641584253F00151A641A" Pok$=Pok$+"84253F0015161514760C42001514640984253F001520641184253F00151C641984253F00151815EE770477047704770477047704A647D6743F001530D674A64214987B0125EAC0078004B5" Pok$=Pok$+"3A1550154E154A15481550154E154A771077F81554770877FC7606641B84753F001522152CA64A25B6A64DD3457304600A25B4A652D3457304600E25B4A65A15B6600F25B4A65A25B6600A" Pok$=Pok$+"25B4A65FD3457306600E15B4D124720800EE6500A6A8F033F2658050300015AA310015AC15B025B4801025B4802015B4F029D345730500EEA664D347FB0AD34700EEA66BD344730200EEA6" Pok$=Pok$+"56D342730300EEA65815D0604015E060A0F015F007300015E200EE600115F06008F01800EEA696FC1EF065400000EE400115CE400325D615D600E0FC29631E640D25B615F4A690FC1E8080" Pok$=Pok$+"F055A696FC1E8090F05500EE88B4606380853F0000EEA68AFC1EF0657001A68AFC1EF055789C00EEF8F8F8F8F8F09090F090F080808080E0A0A0E0404080C0C0F090F0A090D8A8888888F0" Pok$=Pok$+"9010704000700080008000040C1C3C7CFCFCFCFCFCFCFCFF81818181818181FF80808080808080808080808080808000000000000000000000000000000000000000000000" Gosub PokeStringToArray .Rom3 // Pong (Paul Vervalin 1990) Pok$="6A026B0C6C3F6D0CA2EADAB6DCD66E0022D4660368026060F015F0073000121AC717770869FFA2F0D671A2EADAB6DCD66001E0A17BFE6004E0A17B02601F8B02DAB6600CE0A17DFE600DE0" Pok$=Pok$+"A17D02601F8D02DCD6A2F0D67186848794603F8602611F871246021278463F1282471F69FF47006901D671122A68026301807080B5128A68FE630A807080D53F0112A2610280153F0112BA" Pok$=Pok$+"80153F0112C880153F0112C26020F01822D48E3422D4663E3301660368FE33016802121679FF49FE69FF12C87901490269016004F0187601464076FE126CA2F2FE33F265F12964146500D4" Pok$=Pok$+"557415F229D45500EE808080808080800000000000" Gosub PokeStringToArray Goto RomExit .Rom4 // Face from https://chip8.dotslashdan.com/ Pok$="127E24240099423C3200121A120E410000EE81B54100620100EE411A00EE7101411A620000EE33001238122C400000EE80B54000630100EE403800EE70014038630000EEFC073C0000EEE6" Pok$=Pok$+"9E00EE84B3F51500EE2244340012602208222600EEE7A1120EE8A11238E9A1121AEAA1122C00EE00E0D01600EE22542272127860006100630162016400651E66086705680969006A076B01" Pok$=Pok$+"A20222721278" Gosub PokeStringToArray Goto RomExit .Rom5 // Merlin (David Winter).ch8 Pok$="1219204D45524C494E2042792044617669642057494E54455222F9A31D6010610022CBA331600B611B22CB640422DF6500622822C1C2038020A359F51EF05560176108630183223300700A" Pok$=Pok$+"630283223300710AA317D016621422C1D016620522C1750154501235650060176108A317F30A330412796300129733051283700A630112973307128D710A6302129733081269700A710A63" Pok$=Pok$+"03D016621422C1D016A359F51EF0657501503012B55540126922DF7401122D22F9A3456010610E22CB12BFF215F207320012C300EE83006205D015F21E700885307520505012CF00EEA359" Pok$=Pok$+"834073FDF333F265F129602B631BD0357005F229D03500EEA30F60176107D018700AD018710AD01870F6D01800EEFF818181818181FF7E7E7E7E7E7EDBAA8BCBCBEF088F0DECA0A0B030BE" Pok$=Pok$+"5F5151D9D983828382FBE8088805E2BEA0B8203E80808080F8F785B795F576545654563A2A2A2A39B6A5B6A535" Gosub PokeStringToArray Goto RomExit .ROM6 // Keypad Test (Hap, 2006).ch8 (works if chip 8 is disabled - need a clean reboot) Pok$="124E0819010108010F01010908090F09011108110F1101190F191601160916111619FCFCFCFCFCFCFC00A202820EF21E8206F16500EEA202820EF21E8206F15500EE6F10FF15FF073F0012" Pok$=Pok$+"4600EE00E06200222AF229D01570FF71FF2236720132101252F20A222AA222D0172242D0171264" Gosub PokeStringToArray Goto RomExit .ROM7 Pok$="A254F06562018300640B6A1C6B0CA254F21EF165A267DAB7F018F015222CDAB7F115222C72025230120E1200E4A11238F0073000122C00EE6000613C620B00E0A267DAB7F118E2A11244DA" Pok$=Pok$+"B7F018E29E124C1240130A050A050A141E051E051E140A050A050A3C192AC88BC82A19" Gosub PokeStringToArray Goto RomExit .RomExit Return .PokeStringToArray gosub ErrorCheckDisplayAndStop Error$="" L=Len(Pok$) If L==0 Then Error$="StringLen = 0" Return EndIf If 1-(Len(Pok$) & 1) == 0 Then Error$="Not even" Return EndIf For x=0 To L-1 Step 2 y=HexToInt(Mid$(Pok$,x,2)) Mem(PokeStart)=y PokeStart=PokeStart+1 If PokeStart>4096 And (x"" then Print Error$ END EndIf Return .init I=0 Pc=512 StackPointer=0 DelayTimer=0 SoundTimer=0 cycle=0 For x=0 To 15 V(x)=0 Next For x=0 To 15 Stack(x)=0 Next If clrmem==1 Then For x=$200 To TotalMemory-1 Mem(x)=0 Next Else //CopyBank(MemCopy,0,Mem,0,TotalMemory) EndIf Gosub ClearKeys Gosub ClearDisplay clrmem=0 Return .GetTheKeys Gosub ClearKeys For x=0 To 15 If KeyDown(KeyNr(x))==1 Then Keys(x)=1 Next If KeyDown(90)==1 Then Keys(10)=1 Return .ClearKeys For x=0 To 15 Keys(x)=0 Next Return .ClearDisplay For x=0 To 64*32 Display(x)=0 Next Return .DrawScreen c=0 For y=0 To 31 For x=0 To 63 SetColor #0060ff If Display(c)==1 Then SetColor #ffffff Rect (x*SizeX)+SizeX,(y*SizeY)+SizeY,SizeX,SizeY c=c+1 Next Next needRedraw = False SetColor #ffffff Return .MenuButtons MM=0 For x=1 to MenuB(0,0) SetColor #00ffff FillRect MenuB(x,0),MenuB(x,1),MenuB(x,2),MenuB(x,3),0 SetColor #5040ff DrawRect MenuB(x,0),MenuB(x,1),MenuB(x,2),MenuB(x,3),0 SetColor #5050ff Text MenuB(x,0)+2,MenuB(x,1)+7,MenuTxt$(x) If MouseIn(MenuB(x,0),MenuB(x,1),MenuB(x,2),MenuB(x,3),0) then If MoB = 1 Then MM=x EndIf Next SetColor #ffffff Return .DefineMenu FS=9 SetFont 5 SetFontSize FS //MenuMaxBTN=10 MenuTxt$(0)="" MenuB(0,0)=8 TMPX=394 TMPH=FS+3 Tmpnr=0 Tmpnr=tmpnr+1 MenuTxt$(Tmpnr)="Start" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=7 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=tmpnr+1 MenuTxt$(Tmpnr)="Chip8" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=27 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=tmpnr+1 MenuTxt$(Tmpnr)="Chip9" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=87 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=tmpnr+1 MenuTxt$(Tmpnr)="Restart" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=147 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=Tmpnr+1 MenuTxt$(Tmpnr)="Reboot" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=185 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=Tmpnr+1 MenuTxt$(Tmpnr)="Mute" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=47 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=Tmpnr+1 MenuTxt$(Tmpnr)="D-" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX //x coordinate MenuB(Tmpnr,1)=67 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Tmpnr=Tmpnr+1 MenuTxt$(Tmpnr)="D+" TMPW=Len(MenuTxt$(Tmpnr))*10 MenuB(Tmpnr,0)=TMPX+50 //x coordinate MenuB(Tmpnr,1)=67 //y coordinate MenuB(Tmpnr,2)=TMPW //width MenuB(Tmpnr,3)=TMPH //height Return