Advertisement
Kitomas

KIT-8 Emulator

Mar 31st, 2023 (edited)
693
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 23.19 KB | Source Code | 0 0
  1. //idk, like version 1?
  2.  
  3. //#define VERSION_RELEASE (defined automatically)
  4. #define WINDOW_TITLE "KIT-8 Emulator"
  5. #define WINDOW_RES 768,768
  6. #define PI  3.14159265358979323846
  7. #define PI2 6.28318530717958647692
  8.  
  9. #define MIN(a,b) (((a)<(b))?(a):(b))
  10. //#define MAX(a,b) (((a)>(b))?(a):(b))
  11. //#define CLAMP(n, mn,mx) MAX(MIN(n,mx),mn)
  12.  
  13. #include <SDL2/SDL.h>
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <time.h>
  19.  
  20. #include <stdarg.h> //i HOPE this is the only time i use this here
  21. //the whole point of this (basically a wrapper) function is to format the string,
  22.  //and return the pointer to it in the same call (how convenient!)
  23. char _temp_str[1024];
  24. char* fstr(const char* fmt, ...){
  25.   va_list args;
  26.   va_start(args,fmt);
  27.   vsprintf_s(_temp_str,sizeof(_temp_str)-1, fmt,args);
  28.   va_end(args);
  29.   _temp_str[sizeof(_temp_str)-1]=0; //just in case
  30.   return _temp_str;
  31. }
  32. //...and another one for nested calls without the risk of clobbering the other
  33. char _temp_str2[1024];
  34. char* fstr2(const char* fmt, ...){
  35.   va_list args;
  36.   va_start(args,fmt);
  37.   vsprintf_s(_temp_str2,sizeof(_temp_str2)-1, fmt,args);
  38.   va_end(args);
  39.   _temp_str2[sizeof(_temp_str2)-1]=0;
  40.   return _temp_str2;
  41. }
  42.  
  43. typedef union {
  44.   uint16_t value;
  45.   struct {
  46.     uint8_t low;
  47.     uint8_t high;
  48.   };
  49. } r16u_u;
  50. typedef union {
  51.   uint8_t value;
  52.   struct {
  53.     uint8_t operation   : 4;
  54.     uint8_t parameter   : 2;
  55.     uint8_t addressMode : 2;
  56.   };
  57. } opcode_u;
  58. typedef struct {
  59.   uint16_t* MemWatch;
  60.   uint32_t MemWatch_len;
  61.   int32_t FrameWait;
  62.   uint32_t Cycles;
  63.   r16u_u PC,C;
  64.   uint8_t A,I;
  65.   uint8_t MemBank; //32k of low memory + 256 banks of 32k = a little over 8MB!
  66.   union {
  67.     uint8_t S; //noLelzc (MSB -> LSB)
  68.     struct {
  69.       uint8_t Carry             : 1;
  70.       uint8_t Zero              : 1;
  71.       uint8_t LessThanU         : 1;
  72.       uint8_t Equal             : 1;
  73.       uint8_t LessThanS         : 1;
  74.       uint8_t DisableInterrupts : 1;
  75.       uint8_t Overflow          : 1;
  76.       uint8_t Negative          : 1;
  77.     };
  78.   };
  79. } cpu_s;
  80. typedef struct {
  81.   uint32_t* palette; //[256]
  82.   SDL_Color* paletteColors; //[same as palette]
  83.   SDL_Window* window;
  84.   SDL_Renderer* renderer;
  85.   SDL_Texture *T,*S;  //16x16 (256B), 32x32 (1kB)
  86.   SDL_Texture *N,*L;  //64x64 (4kB), 128x128 (16kB)
  87.   uint32_t* pixels;
  88.   int pitch;
  89.   int whichCanvas; //0,1,2,3=T,S,N,L
  90. } canvas_s;
  91.  
  92. typedef struct {
  93.   uint16_t updatesSinceLastCheck;
  94.   uint8_t pressed;
  95. } keyState_s;
  96. typedef struct {
  97.   int16_t* axes; int axes_len;
  98.   uint8_t* hats; int hats_len;
  99.   uint8_t* buttons; int buttons_len;
  100. } joystick_s;
  101.  
  102.  
  103. #define PROGRAM_SIZE_MAX (0x8000 + 0x8000*256) /*32k + 256 banks of 32k*/
  104. cpu_s CPU; canvas_s canvas; SDL_Event event; char* droppedFilePath;
  105. keyState_s keyStates[256]; joystick_s joyStates[5];
  106.  
  107.  
  108. uint32_t getDeltaTime(){ //returns # of ticks since last getDeltaTime()
  109.   static uint32_t timeLast=0xffffffff; //prevents 'initializer element is not constant' error
  110.   if(timeLast==0xffffffff) timeLast=SDL_GetTicks();
  111.   uint32_t timeCurrent=SDL_GetTicks();
  112.   uint32_t timeDelta=timeCurrent-timeLast;
  113.   timeLast=timeCurrent;
  114.   return timeDelta;
  115. }
  116. int loadBinary(const char* fileName,void* buffer,uint32_t memSeek, SDL_Window* window){
  117.   FILE* binFile=fopen(fileName,"rb");
  118.   if(binFile){
  119.     fseek(binFile,0,SEEK_END);
  120.     int binFileSize=ftell(binFile);
  121.     if(binFileSize > PROGRAM_SIZE_MAX){
  122.       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("size of \"%s\" = %u > %uB",fileName,binFileSize,PROGRAM_SIZE_MAX));
  123.       #ifdef VERSION_RELEASE
  124.         if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
  125.       #endif
  126.       return -2;
  127.     } else if(memSeek >= binFileSize){
  128.       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("memSeek = %u > size of \"%s\" (%u)",memSeek,fileName,binFileSize));
  129.       #ifdef VERSION_RELEASE
  130.         if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
  131.       #endif
  132.       return -3;
  133.     } else if(memSeek+binFileSize > PROGRAM_SIZE_MAX){
  134.       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("binary file overflow for \"%s\" @ memSeek=%u",fileName,memSeek));
  135.       #ifdef VERSION_RELEASE
  136.         if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
  137.       #endif
  138.       return -4;
  139.     }
  140.     fseek(binFile,0,SEEK_SET);
  141.     fread(buffer+memSeek,1,binFileSize,binFile);
  142.     return binFileSize;
  143.   } else {
  144.     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("binary file \"%s\" doesn't exist",fileName));
  145.     #ifdef VERSION_RELEASE
  146.       if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
  147.     #endif
  148.     return -1;
  149.   }
  150. }
  151. int blitCanvas(canvas_s* canvas, uint8_t* memory){
  152.   uint32_t *pixels,*palette;
  153.   switch(canvas->whichCanvas){
  154.   case 0:
  155.     if( SDL_LockTexture(canvas->T,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
  156.     memory+=0xff00; pixels=canvas->pixels, palette=canvas->palette;
  157.     for(int i=0; i<0x100; ++i) pixels[i]=palette[memory[i]];
  158.     SDL_UnlockTexture(canvas->T);
  159.     if( SDL_RenderCopy(canvas->renderer,canvas->T, NULL,NULL) ) return -1;
  160.     break;
  161.   case 1:
  162.     if( SDL_LockTexture(canvas->S,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
  163.     memory+=0xfc00; pixels=canvas->pixels, palette=canvas->palette;
  164.     for(int i=0; i<0x400; ++i) pixels[i]=palette[memory[i]];
  165.     SDL_UnlockTexture(canvas->S);
  166.     if( SDL_RenderCopy(canvas->renderer,canvas->S, NULL,NULL) ) return -1;
  167.     break;
  168.   case 2:
  169.     if( SDL_LockTexture(canvas->N,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
  170.     memory+=0xf000; pixels=canvas->pixels, palette=canvas->palette;
  171.     for(int i=0; i<0x1000; ++i) pixels[i]=palette[memory[i]];
  172.     SDL_UnlockTexture(canvas->N);
  173.     if( SDL_RenderCopy(canvas->renderer,canvas->N, NULL,NULL) ) return -1;
  174.     break;
  175.   case 3:
  176.     if( SDL_LockTexture(canvas->L,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
  177.     memory+=0xc000; pixels=canvas->pixels, palette=canvas->palette;
  178.     for(int i=0; i<0x4000; ++i) pixels[i]=palette[memory[i]];
  179.     SDL_UnlockTexture(canvas->L);
  180.     if( SDL_RenderCopy(canvas->renderer,canvas->L, NULL,NULL) ) return -1;
  181.   }
  182.   return 0;
  183. }
  184. //make return not void if needed
  185. void changeWindowTitle(SDL_Window* window, int32_t frameWait, const char* newTitle){
  186.   if(frameWait!=-1){
  187.     SDL_SetWindowTitle(window,fstr2(WINDOW_TITLE" %s",newTitle));
  188.   } else {
  189.     SDL_SetWindowTitle(window,fstr2(WINDOW_TITLE" %s | (paused)",newTitle));
  190.   }
  191. }
  192. //seems to throw 'undefined reference' error if static keyword is not used
  193. static inline uint32_t adjustAddressBanked(uint16_t addr, uint8_t bank){
  194.   if(addr <= 0x7fff) return addr;
  195.   else return 0x8000 + 0x8000*bank + (addr&0x7fff); //(addr&0x7fff)=addr%0x8000
  196. }
  197.  
  198.  
  199. //address modes
  200. uint16_t AM_IndirectLH(cpu_s* CPU, uint8_t* memory){ //^
  201.   ++CPU->PC.value;
  202.   return CPU->C.value;
  203. }
  204. uint16_t AM_Immediate(cpu_s* CPU, uint8_t* memory){ //#
  205.   ++CPU->PC.value;
  206.   return CPU->PC.value++;
  207. }
  208. uint16_t AM_AbsoluteIndexed(cpu_s* CPU, uint8_t* memory){ //@
  209.   r16u_u absAddr;
  210.   absAddr.low =memory[++CPU->PC.value];
  211.   absAddr.high=memory[++CPU->PC.value];
  212.   absAddr.value+=CPU->I;
  213.   ++CPU->PC.value;
  214.   return absAddr.value;
  215. }
  216. uint16_t AM_IndirectIndexed(cpu_s* CPU, uint8_t* memory){ //*
  217.   r16u_u absAddr;
  218.   absAddr.low =memory[++CPU->PC.value];
  219.   absAddr.high=memory[++CPU->PC.value];
  220.   r16u_u indAddr;
  221.   indAddr.low =memory[  absAddr.value];
  222.   indAddr.high=memory[++absAddr.value];
  223.   indAddr.value+=CPU->I;
  224.   ++CPU->PC.value;
  225.   return indAddr.value;
  226. }
  227. uint16_t (*AMS[])(cpu_s* CPU, uint8_t* memory)={
  228.   AM_IndirectLH, AM_Immediate, AM_AbsoluteIndexed, AM_IndirectIndexed
  229. };
  230.  
  231. #define SET_NZ(n) CPU->Negative = (((int32_t)n)&0x80)>>7; CPU->Zero = n==0;
  232. //operations (HCF, JPA, JPR, and BNZ are not included in OPS array)
  233. void OP_INA(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
  234.   switch(parameter){ //I,L,H,C
  235.     case 0: ++CPU->I;       SET_NZ(CPU->I      ); break;
  236.     case 1: ++CPU->C.low;   SET_NZ(CPU->C.low  ); break;
  237.     case 2: ++CPU->C.high;  SET_NZ(CPU->C.high ); break;
  238.     case 3: ++CPU->C.value; SET_NZ(CPU->C.value); break;
  239.   }
  240. }
  241. void OP_TAR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z (ex. S register)
  242.   switch(parameter){ //I,L,H,S
  243.     case 0: CPU->I     =CPU->A; SET_NZ(CPU->I     ); break;
  244.     case 1: CPU->C.low =CPU->A; SET_NZ(CPU->C.low ); break;
  245.     case 2: CPU->C.high=CPU->A; SET_NZ(CPU->C.high); break;
  246.     case 3: CPU->S     =CPU->A;                      break;
  247.   }
  248. }
  249. void OP_TRA(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z (ex. S register)
  250.   switch(parameter){ //I,L,H,S
  251.     case 0: CPU->A=CPU->I;      SET_NZ(CPU->I     ); break;
  252.     case 1: CPU->A=CPU->C.low;  SET_NZ(CPU->C.low ); break;
  253.     case 2: CPU->A=CPU->C.high; SET_NZ(CPU->C.high); break;
  254.     case 3: CPU->A=CPU->S;                           break;
  255.   }
  256. }
  257. void OP_LDR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
  258.   uint8_t value=memory[address]; switch(parameter){ //I,L,H,A
  259.     case 0: CPU->I     =value; SET_NZ(CPU->I     ); break;
  260.     case 1: CPU->C.low =value; SET_NZ(CPU->C.low ); break;
  261.     case 2: CPU->C.high=value; SET_NZ(CPU->C.high); break;
  262.     case 3: CPU->A     =value; SET_NZ(CPU->A     ); break;
  263.   }
  264. }
  265. void OP_STR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //none
  266.   switch(parameter){ //I,L,H,C
  267.     case 0: memory[address]=CPU->I;      break;
  268.     case 1: memory[address]=CPU->C.low;  break;
  269.     case 2: memory[address]=CPU->C.high; break;
  270.     case 3: memory[address]=CPU->A;      break;
  271.   }
  272. }
  273. void OP_ADC(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,o,z,c
  274.   r16u_u sum={.value=(uint16_t)(CPU->A+memory[address]+CPU->Carry)};
  275.   SET_NZ(sum.low); CPU->Carry = sum.value>0xff; //Negative,Zero,Carry
  276.   if(CPU->A<0x80) CPU->Overflow = sum.low>=0x80; //Overflow
  277.   CPU->A=sum.low;
  278. }
  279. void OP_SBC(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,o,z,c
  280.   r16u_u diff={.value=(uint16_t)(CPU->A-memory[address]-(!CPU->Carry))};
  281.   SET_NZ(diff.low); CPU->Carry = !(diff.value>0x7fff); //Negative,Zero,Carry
  282.   if(CPU->A>0x7f) CPU->Overflow = diff.low<=0x7f;//Overflow
  283.   CPU->A=diff.low;
  284. }
  285. void OP_ADD(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,o,z,c
  286.   r16u_u sum={.value=(uint16_t)(CPU->A+memory[address])};
  287.   SET_NZ(sum.low); CPU->Carry = sum.value>0xff; //Negative,Zero,Carry
  288.   if(CPU->A<0x80) CPU->Overflow = sum.low>=0x80; //Overflow
  289.   CPU->A=sum.low;
  290. }
  291. void OP_ROR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z,c
  292.   int amnt=memory[address]&0b111; //amount of bits to rotate right (0 -> 7)
  293.   CPU->A=(CPU->A<<(8-amnt)) | (CPU->A>>amnt);
  294.   SET_NZ(CPU->A); CPU->Carry = (CPU->A&0x80)>>7;
  295. }
  296. void OP_AND(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
  297.   CPU->A&=memory[address]; SET_NZ(CPU->A);
  298. }
  299. void OP_ORA(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
  300.   CPU->A|=memory[address]; SET_NZ(CPU->A);
  301. }
  302. void OP_XOR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
  303.   CPU->A^=memory[address]; SET_NZ(CPU->A);
  304. }
  305. void OP_CMP(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //l,e,L
  306.   uint8_t uA=CPU->A, uO=memory[address]; int8_t sA=uA, sO=uO;
  307.   CPU->LessThanU = uA< uO; //l
  308.   CPU->Equal     = uA==uO; //e
  309.   CPU->LessThanS = sA< sO; //L
  310. }
  311. void OP_SMB(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //none
  312.   CPU->MemBank=memory[address];
  313. }
  314. uint8_t *vram; uint32_t addressB,sysIX,sysIY; uint8_t valA,valB,valC,valD; int8_t valE,valF; //(intentionally outside SYS)
  315. void OP_SYS(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //syscall-dependant
  316.   switch(memory[address]){
  317.   case 0x00: //0x00: wait 1 frame
  318.     CPU->FrameWait=1; break;
  319.   case 0x01: //0x01: wait A # of frames
  320.     CPU->FrameWait=CPU->A; break;
  321.   case 0x02: //0x02: switch canvas size to (16x16 * 2^A)
  322.     canvas.whichCanvas=CPU->A&0b11; break;
  323.   case 0x03: //0x03: set palette color I to (r=A,g=L,b=H)
  324.     parameter=CPU->I; //parameter not used here otherwise, so hopefully this is a bit faster
  325.     canvas.paletteColors[parameter].r=CPU->A;
  326.     canvas.paletteColors[parameter].g=CPU->C.low;
  327.     canvas.paletteColors[parameter].b=CPU->C.high; break;
  328.   case 0x04: //0x04: get palette color I, put into (r=A,g=L,b=H)
  329.     parameter=CPU->I;
  330.     CPU->A     =canvas.paletteColors[parameter].r;
  331.     CPU->C.low =canvas.paletteColors[parameter].g;
  332.     CPU->C.high=canvas.paletteColors[parameter].b; break;
  333.   case 0x05: //0x05: copy 8-bit paletted sprite of x,y,w,h,pixel_0,pixel_1,... to vram (0=transparent)
  334.     address=adjustAddressBanked(CPU->C.value,CPU->MemBank); //start of sprite
  335.     valA=memory[address++], valB=memory[address++]; //x,y
  336.     valC=memory[address++], valD=memory[address++]; //w,h
  337.     switch(canvas.whichCanvas){
  338.     case 0: vram=memory+0xff00; addressB=MIN((int8_t)valA,0x0f) + MIN((int8_t)valB,0x0f)*16;
  339.       for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
  340.         if(++valF <= -1){ address+=valD; addressB+=16; continue; }
  341.         for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
  342.           if(++valE<=0 || valE>16 || addressB>0x80000000){ ++address; ++addressB; continue; }
  343.           if((parameter=memory[address++])) vram[addressB]=parameter;
  344.           if(++addressB >= 256) return;
  345.         } addressB+=16-valC;
  346.       } break;
  347.     case 1: vram=memory+0xfc00; addressB=MIN((int8_t)valA,0x1f) + MIN((int8_t)valB,0x1f)*32;
  348.       for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
  349.         if(++valF <= -1){ address+=valD; addressB+=32; continue; }
  350.         for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
  351.           if(++valE<=0 || valE>32 || addressB>0x80000000){ ++address; ++addressB; continue; }
  352.           if((parameter=memory[address++])) vram[addressB]=parameter;
  353.           if(++addressB >= 1024) return;
  354.         } addressB+=32-valC;
  355.       } break;
  356.     case 2: vram=memory+0xf000; addressB=MIN((int8_t)valA,0x3f) + MIN((int8_t)valB,0x3f)*64;
  357.       for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
  358.         if(++valF <= -1){ address+=valD; addressB+=64; continue; }
  359.         for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
  360.           if(++valE<=0 || valE>64 || addressB>0x80000000){ ++address; ++addressB; continue; }
  361.           if((parameter=memory[address++])) vram[addressB]=parameter;
  362.           if(++addressB >= 4096) return;
  363.         } addressB+=64-valC;
  364.       } break;
  365.     case 3: vram=memory+0xc000; addressB=MIN((int8_t)valA,0x7f) + MIN((int8_t)valB,0x7f)*128;
  366.       for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
  367.         if(++valF <= -1){ address+=valD; addressB+=128; continue; }
  368.         for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
  369.           if(++valE<=0 || valE>128 || addressB>0x80000000){ ++address; ++addressB; continue; }
  370.           if((parameter=memory[address++])) vram[addressB]=parameter;
  371.           if(++addressB >= 16384) return;
  372.         } addressB+=128-valC;
  373.       } break;
  374.     } break;
  375.   case 0xFE: //0xFE: put random value into A
  376.     CPU->A=rand(); break;
  377.   case 0xFF: //0xFF: A=is keyboard keysym pressed?, C=keyState.updatesSinceLastCheck
  378.     CPU->C.value=keyStates[CPU->A].updatesSinceLastCheck;
  379.     keyStates[CPU->A].updatesSinceLastCheck=0;
  380.     CPU->A=keyStates[CPU->A].pressed; break;
  381.   }
  382. }
  383. void (*OPS[])(cpu_s*, uint8_t*, uint32_t, uint8_t)={
  384.     NULL, OP_INA, OP_TAR, OP_TRA, OP_LDR, OP_STR, OP_ADC, OP_SBC,
  385.   OP_ADD, OP_ROR, OP_AND, OP_ORA, OP_XOR, OP_CMP, OP_SMB, OP_SYS,
  386. };
  387.  
  388.  
  389. void resetCPU(cpu_s* CPU){
  390.   memset(CPU,0,sizeof(cpu_s));
  391.   CPU->S=0b00000010; //only zero flag is set
  392. }
  393. void doInstruction(cpu_s* CPU, uint8_t* memory, canvas_s* canvas){
  394.   CPU->FrameWait=0;
  395.   opcode_u opcode={.value=memory[CPU->PC.value]};
  396.   r16u_u address; uint32_t addressBanked;
  397.   switch(opcode.value){
  398.   case 0b00000000: //hcf
  399.     ++CPU->PC.value;
  400.     CPU->FrameWait=-1;
  401.     break;
  402.   case 0b00010000: //jpa
  403.     address.low =memory[++CPU->PC.value];
  404.     address.high=memory[++CPU->PC.value];
  405.     addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
  406.     CPU->PC.value=addressBanked;
  407.     break;
  408.   case 0b00100000: //jpr
  409.     address.value=AM_IndirectLH(CPU,memory);
  410.     addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
  411.     CPU->C.value=CPU->PC.value;
  412.     CPU->PC.low=addressBanked;
  413.     break;
  414.   case 0b00110000: //bnz
  415.     address.value=AM_Immediate(CPU,memory);
  416.     addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
  417.     if(CPU->A) CPU->PC.value+=(int8_t)memory[addressBanked];
  418.     break;
  419.   case 0b01000101: //str i $
  420.   case 0b01010101: //str l $
  421.   case 0b01100101: //str h $
  422.   case 0b01110101: //str a $
  423.     address.low =memory[++CPU->PC.value];
  424.     address.high=memory[++CPU->PC.value]; ++CPU->PC.value;
  425.     addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
  426.     OP_STR(CPU,memory, addressBanked, opcode.parameter); break;
  427.   default: //other instructions, which should follow AAPPIIII opcode pattern
  428.     //operation shouldn't = 0 here (hopefully the only illegal check necessary here)
  429.     if(opcode.operation==0){
  430.       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("Current opcode 0x%X is illegal; program halted.",opcode.value));
  431.       #ifdef VERSION_RELEASE
  432.         if(canvas->window)
  433.           SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Illegal Opcode Detected!",_temp_str,canvas->window);
  434.       #endif
  435.       CPU->FrameWait=-1; break;
  436.     }
  437.     address.value=AMS[opcode.addressMode](CPU,memory);
  438.     addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
  439.     OPS[opcode.operation](CPU,memory, addressBanked, opcode.parameter); break;
  440.   }
  441. }
  442.  
  443.  
  444. #define PREP_ERR(condition) \
  445.   if(condition){ \
  446.     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,SDL_GetError()); \
  447.     SDL_Quit(); return 1; \
  448.   }
  449. #ifndef VERSION_RELEASE
  450. #define B2B_PATT "%c%c%c%c%c%c%c%c"
  451. #define B2B_MCRO(byte)  \
  452.   ((byte) & 0x80 ? '1' : '0'), ((byte) & 0x40 ? '1' : '0'), ((byte) & 0x20 ? '1' : '0'), ((byte) & 0x10 ? '1' : '0'), \
  453.   ((byte) & 0x08 ? '1' : '0'), ((byte) & 0x04 ? '1' : '0'), ((byte) & 0x02 ? '1' : '0'), ((byte) & 0x01 ? '1' : '0')
  454. #define FSTR_CPU fstr("| (PC=%4X), (A=%2X, %4i), (I=%2X, %3u), (C=%4X, %6i), (S=%2X, "B2B_PATT")", \
  455.                       CPU.PC.value, CPU.A,(int8_t)CPU.A, CPU.I,CPU.I, CPU.C.value,CPU.C.value, CPU.S,B2B_MCRO(CPU.S))
  456. #else
  457. #define FSTR_CPU ""
  458. #endif
  459. int main(int argc, char** argv){
  460.   if(SDL_Init(SDL_INIT_VIDEO)){ SDL_Log(SDL_GetError()); return 1; }
  461.  
  462.   //prep + error checks
  463.   memset(&canvas,0,sizeof(canvas_s));
  464.   canvas.window=SDL_CreateWindow( WINDOW_TITLE,
  465.    SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED, WINDOW_RES, SDL_WINDOW_SHOWN );
  466.     PREP_ERR(!canvas.window);
  467.   canvas.renderer=SDL_CreateRenderer(canvas.window,-1,SDL_RENDERER_ACCELERATED);
  468.     PREP_ERR(!canvas.renderer);
  469.   canvas.T=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING,  16, 16);
  470.     PREP_ERR(!canvas.T);
  471.   canvas.S=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING,  32, 32);
  472.     PREP_ERR(!canvas.S);
  473.   canvas.N=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING,  64, 64);
  474.     PREP_ERR(!canvas.N);
  475.   canvas.L=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 128,128);
  476.     PREP_ERR(!canvas.L);
  477.   canvas.whichCanvas=2; //N
  478.   srand((unsigned)time(NULL));
  479.   resetCPU(&CPU);
  480.    //(not explicitly freed unless program exits without error)
  481.   uint8_t* memory=malloc(PROGRAM_SIZE_MAX);
  482.     memset(memory,0,PROGRAM_SIZE_MAX);
  483.     loadBinary("program.bin",memory,0, canvas.window);
  484.     //if(loadBinary("program.bin",memory,0, canvas.window) < 0){ SDL_Quit(); return 1; }
  485.   canvas.palette=malloc(sizeof(uint32_t)*256);
  486.     canvas.paletteColors=(SDL_Color*)canvas.palette;
  487.     FILE* paletteFile=fopen("palette.bin","rb");
  488.     if(!paletteFile){
  489.       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("failed to open \"palette.bin\""));
  490.       #ifdef VERSION_RELEASE
  491.       SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error occurred while loading palette",_temp_str,canvas.window);
  492.       #endif
  493.       SDL_Quit(); return 1;
  494.     }
  495.     fseek(paletteFile,0,SEEK_END);
  496.     int paletteFileSize=ftell(paletteFile);
  497.     if(paletteFileSize != 1024){
  498.       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,"size of \"palette.bin\" must be 1024, not %i",paletteFileSize);
  499.       SDL_Quit(); return 1;
  500.     }
  501.     fseek(paletteFile,0,SEEK_SET);
  502.     fread(canvas.palette,4,256,paletteFile);
  503.     fclose(paletteFile);
  504.  
  505.   #define EVENTWAIT_MAX 64 /* # of iterations/instructions until events update */
  506.   int postInstruction=0,eventWait=0;
  507.   changeWindowTitle(canvas.window,CPU.FrameWait,FSTR_CPU);
  508.   uint32_t timeDelta=getDeltaTime();
  509.   SDL_bool run=SDL_TRUE;
  510.   while(run){
  511.     //event handling
  512.     if(eventWait >= EVENTWAIT_MAX){ eventWait=0;
  513.       while(run && SDL_PollEvent(&event)){ switch(event.type){
  514.         case SDL_QUIT: run=SDL_FALSE; break;
  515.         case SDL_DROPFILE:
  516.           droppedFilePath=event.drop.file;
  517.           if(loadBinary(droppedFilePath,memory,0, canvas.window) >= 0){
  518.             memset(memory,0,PROGRAM_SIZE_MAX); resetCPU(&CPU);
  519.           } else CPU.FrameWait=-1;
  520.           SDL_free(droppedFilePath); break;
  521.         case SDL_KEYDOWN:
  522.           if(event.key.keysym.sym==27 && !event.key.repeat){ //esc key
  523.             CPU.FrameWait=(CPU.FrameWait==-1) ? 0 : -1 ; //? resume : pause;
  524.             changeWindowTitle(canvas.window,CPU.FrameWait,FSTR_CPU);
  525.           } else if(event.key.keysym.sym<256 && !event.key.repeat){
  526.               keyStates[event.key.keysym.sym].pressed=1;
  527.             ++keyStates[event.key.keysym.sym].updatesSinceLastCheck;
  528.           } break;
  529.         case SDL_KEYUP:
  530.           if(event.key.keysym.sym<256 && !event.key.repeat){
  531.               keyStates[event.key.keysym.sym].pressed=0;
  532.             ++keyStates[event.key.keysym.sym].updatesSinceLastCheck;
  533.           } break;
  534.       }}
  535.     }
  536.     if(!CPU.FrameWait){ ++eventWait;
  537.       doInstruction(&CPU,memory,&canvas);
  538.       #ifndef VERSION_RELEASE
  539.         //almost not even necessary to #ifndef this,
  540.          //but it should still be marginally faster
  541.         postInstruction=1;
  542.       #endif
  543.     } else { eventWait=EVENTWAIT_MAX; //immediately process events next iteration
  544.       changeWindowTitle(canvas.window,CPU.FrameWait,FSTR_CPU);
  545.       int blitResult=blitCanvas(&canvas,memory);
  546.       PREP_ERR(blitResult);
  547.       SDL_RenderPresent(canvas.renderer);
  548.       timeDelta=getDeltaTime();
  549.       if(postInstruction){ SDL_Log("timeDelta=%u\n",timeDelta); postInstruction=0; }
  550.       if(timeDelta < 16) SDL_Delay(16-timeDelta); //delay remaining part of 1/60th
  551.       else SDL_Delay(1); //even if timeDelta >= 1/60th, wait at least 1ms
  552.       if(CPU.FrameWait > 0) --CPU.FrameWait;
  553.       timeDelta=getDeltaTime();
  554.     }
  555.   }
  556.  
  557.   //cleaning up
  558.   SDL_DestroyTexture(canvas.L);
  559.   SDL_DestroyTexture(canvas.N);
  560.   SDL_DestroyTexture(canvas.S);
  561.   SDL_DestroyTexture(canvas.T);
  562.   SDL_DestroyRenderer(canvas.renderer);
  563.   SDL_DestroyWindow(canvas.window);
  564.   free(canvas.palette);
  565.   free(memory);
  566.   if(CPU.MemWatch) free(CPU.MemWatch);
  567.   SDL_Quit();
  568.   return 0;
  569. }
  570.  
Tags: kit-8
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement