diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 674 |
1 files changed, 674 insertions, 0 deletions
@@ -0,0 +1,674 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <SDL2/SDL.h> +#include <time.h>//for rand() +#include "main.h" +#include "number_sprites.h" + +//used throughout +int x,y,N; + +unsigned int lastFrame = 0;//number of milliseconds since last frame, wraps around in ~47 days +unsigned int lastTick = 0;//number of milliseconds since tick, wraps around in ~47 days +unsigned int delayTimer = 0;//meant to count down at 60Hz + +//opcodes are two bytes and stored big endian. +int main(int argc, char *argv[]) +{ +srand(time(NULL));//seed pseudorandom number generator + +SDL_Window *window; +SDL_Renderer *renderer; +SDL_Texture *texture; +SDL_Event event; + +if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + exit(3); + } + +window = SDL_CreateWindow("SDL_CreateTexture", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + WIDTH*16, HEIGHT*16, + SDL_WINDOW_RESIZABLE); + +renderer = SDL_CreateRenderer(window, -1, 0); +//renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);//locking to the screen Hz seems to be a stopgap method for now... +texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); + +int pitch; + +uint8_t opcode[2]; + +for(int i = 0; i < 0xF; ++i){V[i] = 0;}//zero out all the registers +for(int i = 0; i < 12; ++i){returnPos[i] = 0;}//zero out the stack + + +if(!argv[1]){fprintf(stderr,"Usage: %s <program>\n", argv[0]); return 1;} + + +//FILE *input = fopen("PONG", "r"); +FILE *input = fopen(argv[1], "r"); +if (!input){fprintf(stderr, "Program not found.\n"); return 1;} + +fseek(input, 0L, SEEK_END); +int size = ftell(input); +rewind(input); + +char *program = malloc(sizeof(char)*size); +if (!program){fprintf(stderr, "Malloc failed!\n"); exit(1);} + +int result = fread(program, 1, size, input); +if (!result){fprintf(stderr, "Fread failed!\n"); exit(1);} +fclose(input);//not needed anymore + +I = program; //point I to the start of the program + +int position = 0;//position in program +while(1) +{ +int ret = SDL_LockTexture(texture, NULL, (void **) &pixels, &pitch); +if (ret != 0){SDL_Log("ret=%d pix=%p error=%s", ret, pixels, SDL_GetError());} + +memcpy(opcode, program+position, 2*sizeof(char)); +position += 2;//read next opcode next time + +int half;//half will equal top half of the first opcode +half = (opcode[0] & 0xF0) >> 4; + +switch (half) + { + case 0x0://0NNN or 00E0 or 00EE + switch(opcode[1]) + { + case 0xE0://00E0 + printf("display_clear()\n"); //clear the screen + display_clear(); + break; + case 0xEE://00EE + printf("return;\n");//return from subroute + position = returnPos[0];//set position back to the stored position + for (int i = 0; i < 11; ++i){returnPos[i] = returnPos[i+1];}//shift all above elements onto the first one to simulate a stack pop + break; + default://0NNN + fprintf(stderr, "RCA 1802 program calling not supported\n"); exit(1); + break; + } + break; + //1NNN + case 0x1: + //below is correct + //the lower 4 bits contain the second char + N = lowerFour(opcode); + N*=0x100;// *= 0x100 sets the correct value for the highest bit + //placeholder + if ((N+opcode[1])-512 < 0){printf("Program writes below 512 bytes\n"); exit(1);} + printf("Jump to address %d\n", (N+opcode[1])-512);//goto NNN + position = (N+opcode[1])-512; + break; + //2NNN + case 0x2: + N = lowerFour(opcode); + N*=0x100; + if ((N+opcode[1])-512 < 0){printf("Program writes below 512 bytes\n"); exit(1);} + printf("Call subroute at %X\n", (N+opcode[1])-512);// *(0xNNN)() + for (int i = 0; i < 11; ++i){returnPos[i+1] = returnPos[i];}//shift up any "stack" contents so any previous return addresses aren't overwritten + returnPos[0] = position;//position is where a subroute should return (the counter is automatically incremented) + position = (N+opcode[1])-512;//just use a jump + break; + case 0x3://3XNN + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + if (V[x] == opcode[1]){position+=2;}//if(Vx==NN), skip the next opcode + printf("3%X%02X\n", x, opcode[1]); + break; + case 0x4://4XNN + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + if (V[x] != opcode[1]){position+=2;}//if(Vx!=NN), skip the next opcode + printf("4%X%02X\n", x, opcode[1]); + break; + case 0x5://5XY0 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + if (V[x] == V[y]){position+=2;}//if(Vx==Vy), skip the next opcode + printf("5%X%X0\n", x, y); + break; + case 0x6://6XNN + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + V[x] = (opcode[1] & 0x00FF);//Vx = NN + printf("6%X%02X\n", x, opcode[1]); + break; + case 0x7://7XNN + //the lower 4 bits contain (V)x + x = lowerFour(opcode); +// V[x] += (opcode[1] & 0x00FF); //Vx += NN +// printf("7%X%02X\n", x, opcode[1]); + V[x] += opcode[1]; //Vx += NN + printf("7%X%02X\n", x, opcode[1]); + break; + case 0x8://8XY0 or 8XY1 or 8XY2 or 8XY3 or 8XY4 or 8XY5 or 8XY6 or 8XY7 or 8XYE + switch(lowerFour(opcode+1)) + { + case 0x0://8XY0 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + V[x] = V[y];//Vx = Vy + printf("8%X%X0\n", x, y); + break; + case 0x1://8XY1 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + V[x] = V[x]|V[y];//Vx = Vx|Vy + printf("8%X%X1\n", x, y); + break; + case 0x2://8XY2 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + V[x] = V[x] & V[y]; //Vx=Vx&Vy + printf("8%X%X2\n", x, y); + break; + case 0x3://8XY3 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + V[x] = V[x] ^ V[y]; //Vx=Vx^Vy + printf("8%X%X3\n", x, y); + break; + case 0x4://8XY4 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + if (V[x] > (0xFF - V[y])) + { + V[0xF] = 1;//carry + printf("Carry\n"); + } + else + { + V[0xF] = 0;//no carry + printf("No carry\n"); + } + V[x] += V[y]; //Vx+=Vy + printf("8%X%X4\n", x, y); + break; + case 0x5://8XY5 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + if (V[y] > V[x]) + { + V[0xF] = 0; + printf("Borrow\n"); + } + else + { + V[0xF] = 1; + printf("No Borrow\n"); + } + V[x] -= V[y]; //Vx-=Vy VF is set to 0 if there's a borrow, and to 1 when there isn't + printf("8%X%X5\n", x, y); + break; + case 0x6://8XY6 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + //Stores the least significant bit of VX in VF + V[0xF] = V[x] & 1; + //and then shifts VX to the right by 1 +// V[x] >>= 1; + //OR + //Set register VF to the least significant bit in V[x] + //Store the value of register VY shifted right one bit in register VX + V[x] = V[y] >> 1; + printf("8%X%X6\n", x, y); + break; + case 0x7://8XY7 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + if (V[x] > V[y]) + { + V[0xF] = 0; + printf("Borrow\n"); + } + else + { + V[0xF] = 1; + printf("No Borrow\n"); + } + V[x] = V[y] - V[x]; //Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't. + printf("8%X%X7\n", x, y); + break; + case 0xE://8XYE + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + //Stores the most significant bit of VX in VF + V[0xF] = (V[x] & 0xFF) >> 7; + //and then shifts VX to the left by 1 + //V[x] <<= 1; + //OR + //Store the value of register VY shifted left one bit in register VX + V[x] = V[y] << 1; + printf("8%X%XE\n", x, y); + break; + default: + fprintf(stderr, "Illegal Instruction\n"); exit(1); + break; + } + break; + case 0x9://9XY0 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits of opcode[1] contains (V)y + y = upperFour(opcode+1); + if (V[x]!=V[y]){printf("Skip next instruction\n"); position+=2;}//skip next instruction if VX != VY. + else{printf("Don't skip next instruction\n");} + break; + case 0xA://ANNN + //the lower 4 bits contain the second char + N = lowerFour(opcode); + N*=0x100;// *= 0x100 sets the correct value for the highest bit + //placeholder + I = program+(N+opcode[1])-512;//I = NNN <-- this does seem to set the position of I correctly + printf("A%03X\n", N); +// printf("Value at I: %c\n", *(I) ); +// exit(1); + break; + case 0xB://BNNN + //the lower 4 bits contain the first 'N' + N = lowerFour(opcode); + N*=0x100;// *= 0x100 sets the correct value for the highest bit + //Jumps to the address NNN plus V0. + printf("Jump to address %X\n", (V[0]+N+opcode[1])-512);//PC=V0+NNN + position = (V[0]+N+opcode[1])-512; + break; + case 0xC://CXNN + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + V[x] = (rand() % 0xFF) & (opcode[1] & 0x00FF);//Vx=rand()&NN + printf("C%X%02X\n", x, opcode[1]); + break; + case 0xD://DXYN + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //the upper 4 bits contain (V)y + y = upperFour(opcode+1); + //the lower 4 bits contain N + N = lowerFour(opcode+1); + printf("D%X%X%X ", x, y, N); + printf("draw(X=%d, Y=%d, %d)\n", V[x], V[y], N); + draw(V[x], V[y], N); + break; + case 0xE://EX9E or EXA1 + switch(opcode[1]) + { + case 0x9E://EX9E + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //skips the next instruction if the key stored in Vx is held down. (non blocking) + SDL_PumpEvents();//pumpEvents() needs to be run unless you would like maybe the last frames keyboard state + const uint8_t *keyBoardState = SDL_GetKeyboardState(NULL);//get keyboard state + //below is more compact than a switch + if (keyBoardState[SDL_SCANCODE_KP_0] && (0 == V[x])){printf("Skip since 0 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_1] && (1 == V[x])){printf("Skip since 1 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_2] && (2 == V[x])){printf("Skip since 2 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_3] && (3 == V[x])){printf("Skip since 3 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_4] && (4 == V[x])){printf("Skip since 4 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_5] && (5 == V[x])){printf("Skip since 5 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_6] && (6 == V[x])){printf("Skip since 6 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_7] && (7 == V[x])){printf("Skip since 7 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_8] && (8 == V[x])){printf("Skip since 8 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_KP_9] && (9 == V[x])){printf("Skip since 9 down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_A] && (0xA == V[x])){printf("Skip since A down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_S] && (0xB == V[x])){printf("Skip since B down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_D] && (0xC == V[x])){printf("Skip since C down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_Z] && (0xD == V[x])){printf("Skip since D down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_X] && (0xE == V[x])){printf("Skip since E down\n"); position+=2; break;} + if (keyBoardState[SDL_SCANCODE_C] && (0xF == V[x])){printf("Skip since F down\n"); position+=2; break;} + printf("E%X9E\n", x); + break; + case 0xA1://EXA1 + //Note: SDL_SCANCODE uses the original key and will know work as expected if keyboard is remapped + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //skips the next instruction if the key stored in Vx isn't pressed. (non blocking, placeholder a) + //below does not register 2 held down keys at once +/* SDL_PumpEvents();//SDL_PumpEvents() is used since SDL_PumpEvent() doesn't seem to register a held down key. + printf("Yes\n"); + switch(V[x])//there should be a better way than this... + { + case 0: + if (event.key.keysym.sym != SDLK_0){printf("Skip since 0 is not held down\n"); position+=2;} + break; + case 1: + if (event.key.keysym.sym != SDLK_1){printf("Skip since 1 is not held down\n"); position+=2;} + break; + case 2: + if (event.key.keysym.sym != SDLK_2){printf("Skip since 2 is not held down\n"); position+=2;} + break; + case 3: + if (event.key.keysym.sym != SDLK_3){printf("Skip since 2 is not held down\n"); position+=2;} + break; + case 4: + if (event.key.keysym.sym != SDLK_4){printf("Skip since 4 is not held down\n"); position+=2;} + break; + case 5: + if (event.key.keysym.sym != SDLK_5){printf("Skip since 5 is not held down\n"); position+=2;} + break; + case 6: + if (event.key.keysym.sym != SDLK_6){printf("Skip since 6 is not held down\n"); position+=2;} + break; + case 7: + if (event.key.keysym.sym != SDLK_7){printf("Skip since 7 is not held down\n"); position+=2;} + break; + case 8: + if (event.key.keysym.sym != SDLK_8){printf("Skip since 8 is not held down\n"); position+=2;} + break; + case 9: + if (event.key.keysym.sym != SDLK_9){printf("Skip since 9 is not held down\n"); position+=2;} + break; + case 0xA: + if (event.key.keysym.sym != SDLK_a){printf("Skip since A is not held down\n"); position+=2;} + break; + case 0xB: + if (event.key.keysym.sym != SDLK_b){printf("Skip since B is not held down\n"); position+=2;} + break; + case 0xC: + if (event.key.keysym.sym != SDLK_c){printf("Skip since C is not held down\n"); position+=2;} + break; + case 0xD: + if (event.key.keysym.sym != SDLK_d){printf("Skip since D is not held down\n"); position+=2;} + break; + case 0xE: + if (event.key.keysym.sym != SDLK_e){printf("Skip since E is not held down\n"); position+=2;} + break; + case 0xF: + if (event.key.keysym.sym != SDLK_f){printf("Skip since F is not held down\n"); position+=2;} + break; + default: + fprintf(stderr, "Value in VX seems to be invalid\n"); + printf("Value is: %X\n", V[x]); + exit(1); + } +*/ + SDL_PumpEvents();//SDL_pumpEvents() is used instead of SDL_pollEvents for many reasons + const uint8_t *notKeyBoardState = SDL_GetKeyboardState(NULL);//get keyboard state + switch(V[x]) + { + case 0: + if (!notKeyBoardState[SDL_SCANCODE_KP_0]){printf("Skip since 0 is not held down\n"); position+=2;} + break; + case 1: + if (!notKeyBoardState[SDL_SCANCODE_KP_1]){printf("Skip since 1 is not held down\n"); position+=2;} + break; + case 2: + if (!notKeyBoardState[SDL_SCANCODE_KP_2]){printf("Skip since 2 is not held down\n"); position+=2;} + break; + case 3: + if (!notKeyBoardState[SDL_SCANCODE_KP_3]){printf("Skip since 2 is not held down\n"); position+=2;} + break; + case 4: + if (!notKeyBoardState[SDL_SCANCODE_KP_4]){printf("Skip since 4 is not held down\n"); position+=2;} + break; + case 5: + if (!notKeyBoardState[SDL_SCANCODE_KP_5]){printf("Skip since 5 is not held down\n"); position+=2;} + break; + case 6: + if (!notKeyBoardState[SDL_SCANCODE_KP_6]){printf("Skip since 6 is not held down\n"); position+=2;} + break; + case 7: + if (!notKeyBoardState[SDL_SCANCODE_KP_7]){printf("Skip since 7 is not held down\n"); position+=2;} + break; + case 8: + if (!notKeyBoardState[SDL_SCANCODE_KP_8]){printf("Skip since 8 is not held down\n"); position+=2;} + break; + case 9: + if (!notKeyBoardState[SDL_SCANCODE_KP_9]){printf("Skip since 9 is not held down\n"); position+=2;} + break; + case 0xA: + if (!notKeyBoardState[SDL_SCANCODE_A]){printf("Skip since A is not held down\n"); position+=2;} + break; + case 0xB: + if (!notKeyBoardState[SDL_SCANCODE_S]){printf("Skip since B is not held down\n"); position+=2;} + break; + case 0xC: + if (!notKeyBoardState[SDL_SCANCODE_D]){printf("Skip since C is not held down\n"); position+=2;} + break; + case 0xD: + if (!notKeyBoardState[SDL_SCANCODE_Z]){printf("Skip since D is not held down\n"); position+=2;} + break; + case 0xE: + if (!notKeyBoardState[SDL_SCANCODE_X]){printf("Skip since E is not held down\n"); position+=2;} + break; + case 0xF: + if (!notKeyBoardState[SDL_SCANCODE_C]){printf("Skip since F is not held down\n"); position+=2;} + break; + default: + fprintf(stderr, "Value in VX is invalid\n"); + printf("Value is: %X\n", V[x]); + exit(1); + } + printf("E%XA1\n", x); + break; + default: + fprintf(stderr, "Illegal Instruction\n"); exit(1); + break; + } + break; + case 0xF://FX07 or FX0A or FX15 or FX18 or FX1E or FX29 or FX33 or FX55 or FX65 + switch (opcode[1]) + { + case 0x07://FX07 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + V[x] = delayTimer; //set VX to the value of the delay timer + printf("V%X = get_delay(%d)\n", x, delayTimer); + break; + case 0x0A://FX0A + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //A key press is awaited, checked to see if valid and then stored in VX. (Blocking Operation) + char c; + anotherChar: if ((c = getchar()) == EOF){free(program); exit(0);} + if (!((c>='0') && (c <='9'))){goto anotherChar;}//get another character if input is invalid + V[x] = c % 10; + printf("F%X0A\n", x); + break; + case 0x15://FX15 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + delayTimer = V[x];//set delayTimer to whatever is in the register + printf("delay_timer(%X)\n", V[x]); +// printf("F%X15\n", x); + break; + case 0x18://FX18 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //The sound timer can be left unimplemeted + printf("sound_timer(%X)\n", V[x]);//set the sound timer to VX + printf("F%X18\n", x); + break; + case 0x1E://FX1E + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + I += V[x];//Adds VX to I. + // VF is set to 1 when there is a range overflow (I+VX>0xFFF), and to 0 when there isn't. + V[0xF] = (*(I)+V[x])>0xFFF; + break; + case 0x29://FX29 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //Sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font. + //while the characters would usually be stored in the interpretor, we just store them elsewhere +// printf("x value: %d\n", x); exit(1); + switch (V[x]) + { + case 0: + I=zero; + break; + case 1: + I=one; + break; + case 2: + I=two; + break; + case 3: + I=three; + break; + case 4: + I=four; + break; + case 5: + I=five; + break; + case 6: + I=six; + break; + case 7: + I=seven; + break; + case 8: + I=eight; + break; + case 9: + I=nine; + break; + case 0xA: + I=A; + break; + case 0xB: + I=B; + break; + case 0xC: + I=C; + break; + case 0xD: + I=D; + break; + case 0xE: + I=E; + break; + case 0xF: + I=F; + break; + default: + printf("sprite_address(x), x out of bounds\n"); + exit(1); + break; + } + printf("F%X29\n", x); + break; + case 0x33://FX33 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //Stores the binary-coded decimal representation of VX, with the most significant of three digits at the address in I, the middle digit at I plus 1, and the least + // significant digit at I plus 2. (In other words, take the decimal representation of VX, place the hundreds digit in memory at location in I, the tens digit at location + //I+1, and the ones digit at location I+2.) + printf("set_BCD(%X)\n", V[x]); + *I = V[x] / 100; + *(I+1) = (V[x] / 10) % 10; + *(I+2) = (V[x] % 100) % 10; + printf("F%X33\n", x); + break; + case 0x55://FX55 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //Stores V0 to VX (including VX) in memory starting at address I. The offset from I is increased by 1 for each value written, but I itself is left unmodified. + for (int i=0; i<=x; ++i) + { + *(I+i) = V[i]; + } + printf("reg_dump(%X)\n", V[x]); + break; + case 0x65://FX65 + //the lower 4 bits contain (V)x + x = lowerFour(opcode); + //Fills V0 to VX (including VX) with values from memory starting at address I. The offset from I is increased by 1 for each value written, but I itself is left unmodified. + for (int i=0; i<=x; ++i)//testy + { + V[i] = *(I+i); + } + printf("reg_load(%X)\n", V[x]);//placeholder + break; + default: + fprintf(stderr, "Illegal Instruction\n"); exit(1); + break; + } + break; + + default: + fprintf(stderr, "Illegal Instruction\n"); exit(1); + break; + } + +printf("Position in program: %ld, opcode:%x%x\n", I-program,opcode[0],opcode[1]); + +if (render)//only render the frame if draw() or clear() was just called +{ +//unlock texture and copy it +SDL_UnlockTexture(texture); +SDL_RenderCopy(renderer, texture, NULL, NULL); + +//Since 1 frame in 60Hz is 16.67ms, which we can't get with a ms timer, 17 ms is used. As a result, frametime (should be) slightly slower than 60Hz. +if (SDL_GetTicks() < (lastFrame+17)){SDL_Delay((lastFrame+17)-SDL_GetTicks());}//SDL_Delay may delay longer than the given value, but it seems to be reasonably accurate. + +SDL_RenderPresent(renderer);//render the frame +lastFrame = SDL_GetTicks();//get the approximate time that the frame was rendered at +render = false;//don't render until draw() or clear() is called +} + + +if (SDL_GetTicks() < (lastTick+2)){SDL_Delay((lastTick+2)-SDL_GetTicks());}//limit clockrate to ~500Hz (too fast for some games, the right speed for some too) +if (delayTimer && (SDL_GetTicks()%16 == 0)||(SDL_GetTicks()%16 == 1) ){--delayTimer;}//deincrement the delay timer if nonzero (delay timer is meant to count down at 60Hz, % 16 on the total runtime ticks seems be roughly correct). + +lastTick = SDL_GetTicks(); + +/* +getchar();//step through each instruction +printf("Step\n"); +*/ +/* +for (int i=0; i<0xF+1; ++i) + { + printf("V%X: %d\t", i, V[i]); + } +*/ +/* +printf("Position: %d\t", position); +printf("I: %ld", I-program); + +putchar('\n'); +*/ + +//SDL_Delay(40);//want to watch the output slowly +SDL_PollEvent(&event); +if (event.type == SDL_QUIT){break;}//exit if the quit signal is given +} + +SDL_DestroyRenderer(renderer); +SDL_Quit(); +free(program); + +return 0; +} |