Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //idk, like version 1?
- //#define VERSION_RELEASE (defined automatically)
- #define WINDOW_TITLE "KIT-8 Emulator"
- #define WINDOW_RES 768,768
- #define PI 3.14159265358979323846
- #define PI2 6.28318530717958647692
- #define MIN(a,b) (((a)<(b))?(a):(b))
- //#define MAX(a,b) (((a)>(b))?(a):(b))
- //#define CLAMP(n, mn,mx) MAX(MIN(n,mx),mn)
- #include <SDL2/SDL.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <stdarg.h> //i HOPE this is the only time i use this here
- //the whole point of this (basically a wrapper) function is to format the string,
- //and return the pointer to it in the same call (how convenient!)
- char _temp_str[1024];
- char* fstr(const char* fmt, ...){
- va_list args;
- va_start(args,fmt);
- vsprintf_s(_temp_str,sizeof(_temp_str)-1, fmt,args);
- va_end(args);
- _temp_str[sizeof(_temp_str)-1]=0; //just in case
- return _temp_str;
- }
- //...and another one for nested calls without the risk of clobbering the other
- char _temp_str2[1024];
- char* fstr2(const char* fmt, ...){
- va_list args;
- va_start(args,fmt);
- vsprintf_s(_temp_str2,sizeof(_temp_str2)-1, fmt,args);
- va_end(args);
- _temp_str2[sizeof(_temp_str2)-1]=0;
- return _temp_str2;
- }
- typedef union {
- uint16_t value;
- struct {
- uint8_t low;
- uint8_t high;
- };
- } r16u_u;
- typedef union {
- uint8_t value;
- struct {
- uint8_t operation : 4;
- uint8_t parameter : 2;
- uint8_t addressMode : 2;
- };
- } opcode_u;
- typedef struct {
- uint16_t* MemWatch;
- uint32_t MemWatch_len;
- int32_t FrameWait;
- uint32_t Cycles;
- r16u_u PC,C;
- uint8_t A,I;
- uint8_t MemBank; //32k of low memory + 256 banks of 32k = a little over 8MB!
- union {
- uint8_t S; //noLelzc (MSB -> LSB)
- struct {
- uint8_t Carry : 1;
- uint8_t Zero : 1;
- uint8_t LessThanU : 1;
- uint8_t Equal : 1;
- uint8_t LessThanS : 1;
- uint8_t DisableInterrupts : 1;
- uint8_t Overflow : 1;
- uint8_t Negative : 1;
- };
- };
- } cpu_s;
- typedef struct {
- uint32_t* palette; //[256]
- SDL_Color* paletteColors; //[same as palette]
- SDL_Window* window;
- SDL_Renderer* renderer;
- SDL_Texture *T,*S; //16x16 (256B), 32x32 (1kB)
- SDL_Texture *N,*L; //64x64 (4kB), 128x128 (16kB)
- uint32_t* pixels;
- int pitch;
- int whichCanvas; //0,1,2,3=T,S,N,L
- } canvas_s;
- typedef struct {
- uint16_t updatesSinceLastCheck;
- uint8_t pressed;
- } keyState_s;
- typedef struct {
- int16_t* axes; int axes_len;
- uint8_t* hats; int hats_len;
- uint8_t* buttons; int buttons_len;
- } joystick_s;
- #define PROGRAM_SIZE_MAX (0x8000 + 0x8000*256) /*32k + 256 banks of 32k*/
- cpu_s CPU; canvas_s canvas; SDL_Event event; char* droppedFilePath;
- keyState_s keyStates[256]; joystick_s joyStates[5];
- uint32_t getDeltaTime(){ //returns # of ticks since last getDeltaTime()
- static uint32_t timeLast=0xffffffff; //prevents 'initializer element is not constant' error
- if(timeLast==0xffffffff) timeLast=SDL_GetTicks();
- uint32_t timeCurrent=SDL_GetTicks();
- uint32_t timeDelta=timeCurrent-timeLast;
- timeLast=timeCurrent;
- return timeDelta;
- }
- int loadBinary(const char* fileName,void* buffer,uint32_t memSeek, SDL_Window* window){
- FILE* binFile=fopen(fileName,"rb");
- if(binFile){
- fseek(binFile,0,SEEK_END);
- int binFileSize=ftell(binFile);
- if(binFileSize > PROGRAM_SIZE_MAX){
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("size of \"%s\" = %u > %uB",fileName,binFileSize,PROGRAM_SIZE_MAX));
- #ifdef VERSION_RELEASE
- if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
- #endif
- return -2;
- } else if(memSeek >= binFileSize){
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("memSeek = %u > size of \"%s\" (%u)",memSeek,fileName,binFileSize));
- #ifdef VERSION_RELEASE
- if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
- #endif
- return -3;
- } else if(memSeek+binFileSize > PROGRAM_SIZE_MAX){
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("binary file overflow for \"%s\" @ memSeek=%u",fileName,memSeek));
- #ifdef VERSION_RELEASE
- if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
- #endif
- return -4;
- }
- fseek(binFile,0,SEEK_SET);
- fread(buffer+memSeek,1,binFileSize,binFile);
- return binFileSize;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("binary file \"%s\" doesn't exist",fileName));
- #ifdef VERSION_RELEASE
- if(window) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error loading binary file!",_temp_str,window);
- #endif
- return -1;
- }
- }
- int blitCanvas(canvas_s* canvas, uint8_t* memory){
- uint32_t *pixels,*palette;
- switch(canvas->whichCanvas){
- case 0:
- if( SDL_LockTexture(canvas->T,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
- memory+=0xff00; pixels=canvas->pixels, palette=canvas->palette;
- for(int i=0; i<0x100; ++i) pixels[i]=palette[memory[i]];
- SDL_UnlockTexture(canvas->T);
- if( SDL_RenderCopy(canvas->renderer,canvas->T, NULL,NULL) ) return -1;
- break;
- case 1:
- if( SDL_LockTexture(canvas->S,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
- memory+=0xfc00; pixels=canvas->pixels, palette=canvas->palette;
- for(int i=0; i<0x400; ++i) pixels[i]=palette[memory[i]];
- SDL_UnlockTexture(canvas->S);
- if( SDL_RenderCopy(canvas->renderer,canvas->S, NULL,NULL) ) return -1;
- break;
- case 2:
- if( SDL_LockTexture(canvas->N,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
- memory+=0xf000; pixels=canvas->pixels, palette=canvas->palette;
- for(int i=0; i<0x1000; ++i) pixels[i]=palette[memory[i]];
- SDL_UnlockTexture(canvas->N);
- if( SDL_RenderCopy(canvas->renderer,canvas->N, NULL,NULL) ) return -1;
- break;
- case 3:
- if( SDL_LockTexture(canvas->L,NULL,(void**)(&canvas->pixels),&canvas->pitch) ) return -1;
- memory+=0xc000; pixels=canvas->pixels, palette=canvas->palette;
- for(int i=0; i<0x4000; ++i) pixels[i]=palette[memory[i]];
- SDL_UnlockTexture(canvas->L);
- if( SDL_RenderCopy(canvas->renderer,canvas->L, NULL,NULL) ) return -1;
- }
- return 0;
- }
- //make return not void if needed
- void changeWindowTitle(SDL_Window* window, int32_t frameWait, const char* newTitle){
- if(frameWait!=-1){
- SDL_SetWindowTitle(window,fstr2(WINDOW_TITLE" %s",newTitle));
- } else {
- SDL_SetWindowTitle(window,fstr2(WINDOW_TITLE" %s | (paused)",newTitle));
- }
- }
- //seems to throw 'undefined reference' error if static keyword is not used
- static inline uint32_t adjustAddressBanked(uint16_t addr, uint8_t bank){
- if(addr <= 0x7fff) return addr;
- else return 0x8000 + 0x8000*bank + (addr&0x7fff); //(addr&0x7fff)=addr%0x8000
- }
- //address modes
- uint16_t AM_IndirectLH(cpu_s* CPU, uint8_t* memory){ //^
- ++CPU->PC.value;
- return CPU->C.value;
- }
- uint16_t AM_Immediate(cpu_s* CPU, uint8_t* memory){ //#
- ++CPU->PC.value;
- return CPU->PC.value++;
- }
- uint16_t AM_AbsoluteIndexed(cpu_s* CPU, uint8_t* memory){ //@
- r16u_u absAddr;
- absAddr.low =memory[++CPU->PC.value];
- absAddr.high=memory[++CPU->PC.value];
- absAddr.value+=CPU->I;
- ++CPU->PC.value;
- return absAddr.value;
- }
- uint16_t AM_IndirectIndexed(cpu_s* CPU, uint8_t* memory){ //*
- r16u_u absAddr;
- absAddr.low =memory[++CPU->PC.value];
- absAddr.high=memory[++CPU->PC.value];
- r16u_u indAddr;
- indAddr.low =memory[ absAddr.value];
- indAddr.high=memory[++absAddr.value];
- indAddr.value+=CPU->I;
- ++CPU->PC.value;
- return indAddr.value;
- }
- uint16_t (*AMS[])(cpu_s* CPU, uint8_t* memory)={
- AM_IndirectLH, AM_Immediate, AM_AbsoluteIndexed, AM_IndirectIndexed
- };
- #define SET_NZ(n) CPU->Negative = (((int32_t)n)&0x80)>>7; CPU->Zero = n==0;
- //operations (HCF, JPA, JPR, and BNZ are not included in OPS array)
- void OP_INA(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
- switch(parameter){ //I,L,H,C
- case 0: ++CPU->I; SET_NZ(CPU->I ); break;
- case 1: ++CPU->C.low; SET_NZ(CPU->C.low ); break;
- case 2: ++CPU->C.high; SET_NZ(CPU->C.high ); break;
- case 3: ++CPU->C.value; SET_NZ(CPU->C.value); break;
- }
- }
- void OP_TAR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z (ex. S register)
- switch(parameter){ //I,L,H,S
- case 0: CPU->I =CPU->A; SET_NZ(CPU->I ); break;
- case 1: CPU->C.low =CPU->A; SET_NZ(CPU->C.low ); break;
- case 2: CPU->C.high=CPU->A; SET_NZ(CPU->C.high); break;
- case 3: CPU->S =CPU->A; break;
- }
- }
- void OP_TRA(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z (ex. S register)
- switch(parameter){ //I,L,H,S
- case 0: CPU->A=CPU->I; SET_NZ(CPU->I ); break;
- case 1: CPU->A=CPU->C.low; SET_NZ(CPU->C.low ); break;
- case 2: CPU->A=CPU->C.high; SET_NZ(CPU->C.high); break;
- case 3: CPU->A=CPU->S; break;
- }
- }
- void OP_LDR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
- uint8_t value=memory[address]; switch(parameter){ //I,L,H,A
- case 0: CPU->I =value; SET_NZ(CPU->I ); break;
- case 1: CPU->C.low =value; SET_NZ(CPU->C.low ); break;
- case 2: CPU->C.high=value; SET_NZ(CPU->C.high); break;
- case 3: CPU->A =value; SET_NZ(CPU->A ); break;
- }
- }
- void OP_STR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //none
- switch(parameter){ //I,L,H,C
- case 0: memory[address]=CPU->I; break;
- case 1: memory[address]=CPU->C.low; break;
- case 2: memory[address]=CPU->C.high; break;
- case 3: memory[address]=CPU->A; break;
- }
- }
- void OP_ADC(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,o,z,c
- r16u_u sum={.value=(uint16_t)(CPU->A+memory[address]+CPU->Carry)};
- SET_NZ(sum.low); CPU->Carry = sum.value>0xff; //Negative,Zero,Carry
- if(CPU->A<0x80) CPU->Overflow = sum.low>=0x80; //Overflow
- CPU->A=sum.low;
- }
- void OP_SBC(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,o,z,c
- r16u_u diff={.value=(uint16_t)(CPU->A-memory[address]-(!CPU->Carry))};
- SET_NZ(diff.low); CPU->Carry = !(diff.value>0x7fff); //Negative,Zero,Carry
- if(CPU->A>0x7f) CPU->Overflow = diff.low<=0x7f;//Overflow
- CPU->A=diff.low;
- }
- void OP_ADD(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,o,z,c
- r16u_u sum={.value=(uint16_t)(CPU->A+memory[address])};
- SET_NZ(sum.low); CPU->Carry = sum.value>0xff; //Negative,Zero,Carry
- if(CPU->A<0x80) CPU->Overflow = sum.low>=0x80; //Overflow
- CPU->A=sum.low;
- }
- void OP_ROR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z,c
- int amnt=memory[address]&0b111; //amount of bits to rotate right (0 -> 7)
- CPU->A=(CPU->A<<(8-amnt)) | (CPU->A>>amnt);
- SET_NZ(CPU->A); CPU->Carry = (CPU->A&0x80)>>7;
- }
- void OP_AND(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
- CPU->A&=memory[address]; SET_NZ(CPU->A);
- }
- void OP_ORA(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
- CPU->A|=memory[address]; SET_NZ(CPU->A);
- }
- void OP_XOR(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //n,z
- CPU->A^=memory[address]; SET_NZ(CPU->A);
- }
- void OP_CMP(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //l,e,L
- uint8_t uA=CPU->A, uO=memory[address]; int8_t sA=uA, sO=uO;
- CPU->LessThanU = uA< uO; //l
- CPU->Equal = uA==uO; //e
- CPU->LessThanS = sA< sO; //L
- }
- void OP_SMB(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //none
- CPU->MemBank=memory[address];
- }
- uint8_t *vram; uint32_t addressB,sysIX,sysIY; uint8_t valA,valB,valC,valD; int8_t valE,valF; //(intentionally outside SYS)
- void OP_SYS(cpu_s* CPU, uint8_t* memory, uint32_t address, uint8_t parameter){ //syscall-dependant
- switch(memory[address]){
- case 0x00: //0x00: wait 1 frame
- CPU->FrameWait=1; break;
- case 0x01: //0x01: wait A # of frames
- CPU->FrameWait=CPU->A; break;
- case 0x02: //0x02: switch canvas size to (16x16 * 2^A)
- canvas.whichCanvas=CPU->A&0b11; break;
- case 0x03: //0x03: set palette color I to (r=A,g=L,b=H)
- parameter=CPU->I; //parameter not used here otherwise, so hopefully this is a bit faster
- canvas.paletteColors[parameter].r=CPU->A;
- canvas.paletteColors[parameter].g=CPU->C.low;
- canvas.paletteColors[parameter].b=CPU->C.high; break;
- case 0x04: //0x04: get palette color I, put into (r=A,g=L,b=H)
- parameter=CPU->I;
- CPU->A =canvas.paletteColors[parameter].r;
- CPU->C.low =canvas.paletteColors[parameter].g;
- CPU->C.high=canvas.paletteColors[parameter].b; break;
- case 0x05: //0x05: copy 8-bit paletted sprite of x,y,w,h,pixel_0,pixel_1,... to vram (0=transparent)
- address=adjustAddressBanked(CPU->C.value,CPU->MemBank); //start of sprite
- valA=memory[address++], valB=memory[address++]; //x,y
- valC=memory[address++], valD=memory[address++]; //w,h
- switch(canvas.whichCanvas){
- case 0: vram=memory+0xff00; addressB=MIN((int8_t)valA,0x0f) + MIN((int8_t)valB,0x0f)*16;
- for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
- if(++valF <= -1){ address+=valD; addressB+=16; continue; }
- for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
- if(++valE<=0 || valE>16 || addressB>0x80000000){ ++address; ++addressB; continue; }
- if((parameter=memory[address++])) vram[addressB]=parameter;
- if(++addressB >= 256) return;
- } addressB+=16-valC;
- } break;
- case 1: vram=memory+0xfc00; addressB=MIN((int8_t)valA,0x1f) + MIN((int8_t)valB,0x1f)*32;
- for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
- if(++valF <= -1){ address+=valD; addressB+=32; continue; }
- for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
- if(++valE<=0 || valE>32 || addressB>0x80000000){ ++address; ++addressB; continue; }
- if((parameter=memory[address++])) vram[addressB]=parameter;
- if(++addressB >= 1024) return;
- } addressB+=32-valC;
- } break;
- case 2: vram=memory+0xf000; addressB=MIN((int8_t)valA,0x3f) + MIN((int8_t)valB,0x3f)*64;
- for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
- if(++valF <= -1){ address+=valD; addressB+=64; continue; }
- for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
- if(++valE<=0 || valE>64 || addressB>0x80000000){ ++address; ++addressB; continue; }
- if((parameter=memory[address++])) vram[addressB]=parameter;
- if(++addressB >= 4096) return;
- } addressB+=64-valC;
- } break;
- case 3: vram=memory+0xc000; addressB=MIN((int8_t)valA,0x7f) + MIN((int8_t)valB,0x7f)*128;
- for(sysIY=0,valF=valB; sysIY<valD; ++sysIY){
- if(++valF <= -1){ address+=valD; addressB+=128; continue; }
- for(sysIX=0,valE=valA; sysIX<valC; ++sysIX){
- if(++valE<=0 || valE>128 || addressB>0x80000000){ ++address; ++addressB; continue; }
- if((parameter=memory[address++])) vram[addressB]=parameter;
- if(++addressB >= 16384) return;
- } addressB+=128-valC;
- } break;
- } break;
- case 0xFE: //0xFE: put random value into A
- CPU->A=rand(); break;
- case 0xFF: //0xFF: A=is keyboard keysym pressed?, C=keyState.updatesSinceLastCheck
- CPU->C.value=keyStates[CPU->A].updatesSinceLastCheck;
- keyStates[CPU->A].updatesSinceLastCheck=0;
- CPU->A=keyStates[CPU->A].pressed; break;
- }
- }
- void (*OPS[])(cpu_s*, uint8_t*, uint32_t, uint8_t)={
- NULL, OP_INA, OP_TAR, OP_TRA, OP_LDR, OP_STR, OP_ADC, OP_SBC,
- OP_ADD, OP_ROR, OP_AND, OP_ORA, OP_XOR, OP_CMP, OP_SMB, OP_SYS,
- };
- void resetCPU(cpu_s* CPU){
- memset(CPU,0,sizeof(cpu_s));
- CPU->S=0b00000010; //only zero flag is set
- }
- void doInstruction(cpu_s* CPU, uint8_t* memory, canvas_s* canvas){
- CPU->FrameWait=0;
- opcode_u opcode={.value=memory[CPU->PC.value]};
- r16u_u address; uint32_t addressBanked;
- switch(opcode.value){
- case 0b00000000: //hcf
- ++CPU->PC.value;
- CPU->FrameWait=-1;
- break;
- case 0b00010000: //jpa
- address.low =memory[++CPU->PC.value];
- address.high=memory[++CPU->PC.value];
- addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
- CPU->PC.value=addressBanked;
- break;
- case 0b00100000: //jpr
- address.value=AM_IndirectLH(CPU,memory);
- addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
- CPU->C.value=CPU->PC.value;
- CPU->PC.low=addressBanked;
- break;
- case 0b00110000: //bnz
- address.value=AM_Immediate(CPU,memory);
- addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
- if(CPU->A) CPU->PC.value+=(int8_t)memory[addressBanked];
- break;
- case 0b01000101: //str i $
- case 0b01010101: //str l $
- case 0b01100101: //str h $
- case 0b01110101: //str a $
- address.low =memory[++CPU->PC.value];
- address.high=memory[++CPU->PC.value]; ++CPU->PC.value;
- addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
- OP_STR(CPU,memory, addressBanked, opcode.parameter); break;
- default: //other instructions, which should follow AAPPIIII opcode pattern
- //operation shouldn't = 0 here (hopefully the only illegal check necessary here)
- if(opcode.operation==0){
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("Current opcode 0x%X is illegal; program halted.",opcode.value));
- #ifdef VERSION_RELEASE
- if(canvas->window)
- SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Illegal Opcode Detected!",_temp_str,canvas->window);
- #endif
- CPU->FrameWait=-1; break;
- }
- address.value=AMS[opcode.addressMode](CPU,memory);
- addressBanked=adjustAddressBanked(address.value,CPU->MemBank);
- OPS[opcode.operation](CPU,memory, addressBanked, opcode.parameter); break;
- }
- }
- #define PREP_ERR(condition) \
- if(condition){ \
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,SDL_GetError()); \
- SDL_Quit(); return 1; \
- }
- #ifndef VERSION_RELEASE
- #define B2B_PATT "%c%c%c%c%c%c%c%c"
- #define B2B_MCRO(byte) \
- ((byte) & 0x80 ? '1' : '0'), ((byte) & 0x40 ? '1' : '0'), ((byte) & 0x20 ? '1' : '0'), ((byte) & 0x10 ? '1' : '0'), \
- ((byte) & 0x08 ? '1' : '0'), ((byte) & 0x04 ? '1' : '0'), ((byte) & 0x02 ? '1' : '0'), ((byte) & 0x01 ? '1' : '0')
- #define FSTR_CPU fstr("| (PC=%4X), (A=%2X, %4i), (I=%2X, %3u), (C=%4X, %6i), (S=%2X, "B2B_PATT")", \
- 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))
- #else
- #define FSTR_CPU ""
- #endif
- int main(int argc, char** argv){
- if(SDL_Init(SDL_INIT_VIDEO)){ SDL_Log(SDL_GetError()); return 1; }
- //prep + error checks
- memset(&canvas,0,sizeof(canvas_s));
- canvas.window=SDL_CreateWindow( WINDOW_TITLE,
- SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED, WINDOW_RES, SDL_WINDOW_SHOWN );
- PREP_ERR(!canvas.window);
- canvas.renderer=SDL_CreateRenderer(canvas.window,-1,SDL_RENDERER_ACCELERATED);
- PREP_ERR(!canvas.renderer);
- canvas.T=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 16, 16);
- PREP_ERR(!canvas.T);
- canvas.S=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 32, 32);
- PREP_ERR(!canvas.S);
- canvas.N=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 64, 64);
- PREP_ERR(!canvas.N);
- canvas.L=SDL_CreateTexture(canvas.renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 128,128);
- PREP_ERR(!canvas.L);
- canvas.whichCanvas=2; //N
- srand((unsigned)time(NULL));
- resetCPU(&CPU);
- //(not explicitly freed unless program exits without error)
- uint8_t* memory=malloc(PROGRAM_SIZE_MAX);
- memset(memory,0,PROGRAM_SIZE_MAX);
- loadBinary("program.bin",memory,0, canvas.window);
- //if(loadBinary("program.bin",memory,0, canvas.window) < 0){ SDL_Quit(); return 1; }
- canvas.palette=malloc(sizeof(uint32_t)*256);
- canvas.paletteColors=(SDL_Color*)canvas.palette;
- FILE* paletteFile=fopen("palette.bin","rb");
- if(!paletteFile){
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,fstr("failed to open \"palette.bin\""));
- #ifdef VERSION_RELEASE
- SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,"Error occurred while loading palette",_temp_str,canvas.window);
- #endif
- SDL_Quit(); return 1;
- }
- fseek(paletteFile,0,SEEK_END);
- int paletteFileSize=ftell(paletteFile);
- if(paletteFileSize != 1024){
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,"size of \"palette.bin\" must be 1024, not %i",paletteFileSize);
- SDL_Quit(); return 1;
- }
- fseek(paletteFile,0,SEEK_SET);
- fread(canvas.palette,4,256,paletteFile);
- fclose(paletteFile);
- #define EVENTWAIT_MAX 64 /* # of iterations/instructions until events update */
- int postInstruction=0,eventWait=0;
- changeWindowTitle(canvas.window,CPU.FrameWait,FSTR_CPU);
- uint32_t timeDelta=getDeltaTime();
- SDL_bool run=SDL_TRUE;
- while(run){
- //event handling
- if(eventWait >= EVENTWAIT_MAX){ eventWait=0;
- while(run && SDL_PollEvent(&event)){ switch(event.type){
- case SDL_QUIT: run=SDL_FALSE; break;
- case SDL_DROPFILE:
- droppedFilePath=event.drop.file;
- if(loadBinary(droppedFilePath,memory,0, canvas.window) >= 0){
- memset(memory,0,PROGRAM_SIZE_MAX); resetCPU(&CPU);
- } else CPU.FrameWait=-1;
- SDL_free(droppedFilePath); break;
- case SDL_KEYDOWN:
- if(event.key.keysym.sym==27 && !event.key.repeat){ //esc key
- CPU.FrameWait=(CPU.FrameWait==-1) ? 0 : -1 ; //? resume : pause;
- changeWindowTitle(canvas.window,CPU.FrameWait,FSTR_CPU);
- } else if(event.key.keysym.sym<256 && !event.key.repeat){
- keyStates[event.key.keysym.sym].pressed=1;
- ++keyStates[event.key.keysym.sym].updatesSinceLastCheck;
- } break;
- case SDL_KEYUP:
- if(event.key.keysym.sym<256 && !event.key.repeat){
- keyStates[event.key.keysym.sym].pressed=0;
- ++keyStates[event.key.keysym.sym].updatesSinceLastCheck;
- } break;
- }}
- }
- if(!CPU.FrameWait){ ++eventWait;
- doInstruction(&CPU,memory,&canvas);
- #ifndef VERSION_RELEASE
- //almost not even necessary to #ifndef this,
- //but it should still be marginally faster
- postInstruction=1;
- #endif
- } else { eventWait=EVENTWAIT_MAX; //immediately process events next iteration
- changeWindowTitle(canvas.window,CPU.FrameWait,FSTR_CPU);
- int blitResult=blitCanvas(&canvas,memory);
- PREP_ERR(blitResult);
- SDL_RenderPresent(canvas.renderer);
- timeDelta=getDeltaTime();
- if(postInstruction){ SDL_Log("timeDelta=%u\n",timeDelta); postInstruction=0; }
- if(timeDelta < 16) SDL_Delay(16-timeDelta); //delay remaining part of 1/60th
- else SDL_Delay(1); //even if timeDelta >= 1/60th, wait at least 1ms
- if(CPU.FrameWait > 0) --CPU.FrameWait;
- timeDelta=getDeltaTime();
- }
- }
- //cleaning up
- SDL_DestroyTexture(canvas.L);
- SDL_DestroyTexture(canvas.N);
- SDL_DestroyTexture(canvas.S);
- SDL_DestroyTexture(canvas.T);
- SDL_DestroyRenderer(canvas.renderer);
- SDL_DestroyWindow(canvas.window);
- free(canvas.palette);
- free(memory);
- if(CPU.MemWatch) free(CPU.MemWatch);
- SDL_Quit();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement