Example #1
0
int main(int argc, char * argv[]) {
    if (argc != 2) {
        usage(argv[0]);
        exit(1);
    }
    
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("Echec init : %s\n", SDL_GetError());
        exit(1);
    }

    GBContext   *cpu = cpu_init(argv[1]);
    GPUContext  *gpu = gpu_init(cpu);
    JOYPContext *joyp = joyp_init(cpu);
    
    uint8_t op;
    unsigned int start_time, last_time, elapsed_time;
    while (!cpu->exit) {
        start_time = SDL_GetTicks();

        while (cpu->t_clock < VSYNC_CYCLES) {
            op = read8(cpu, cpu->PC++);
            execute(cpu, op);
            
            //"realtime" operations must be here..
            cpu_ctx_update(cpu);
            gpu_ctx_update(cpu, gpu);
            joyp_ctx_update(cpu, joyp);
            handle_interrupt(cpu);
        }
        cpu->t_clock = 0;

        last_time = SDL_GetTicks();
        elapsed_time = last_time - start_time;
        if(elapsed_time < VSYNC_TIME_MS) {// just a basic frame rate wait loop
            SDL_Delay(VSYNC_TIME_MS - elapsed_time);
        }
        
        gpu_render(cpu, gpu);
//        printf("elapsed: %d\n", elapsed_time);
    }

    
    joyp_destroy(joyp);
    gpu_destroy(gpu);
    cpu_destroy(cpu);
    SDL_Quit();

    return 0;
}
Example #2
0
// Timing from http://imrannazar.com/GameBoy-Emulation-in-JavaScript:-GPU-Timings
void gpu_process(gpu* gp, interrupts* ir, uint16_t clock) {

	gp->state_start_clock += clock;
	switch(GPU_GET_MODE(gp)) {
	case GPU_HORIZ_BLANK:
		if (gp->state_start_clock >= GPU_HORIZ_BLANK_TIMING) {
			gp->state_start_clock = 0;
			gp->reg.cur_line++;

			if (gp->reg.cur_line == SCREEN_HEIGHT) {
				GPU_SET_MODE(gp, GPU_VERT_BLANK);
				// Redraw surface
				SDL_Flip(gp->surface);

				// Raise irq
				if (gp->reg.control & 0x80)
					interrupts_raise(ir, IRQ_VBLANK);

				if ((gp->reg.status & (1 << 4)))
					interrupts_raise(ir, IRQ_LCD);

			} else {
				if ((gp->reg.status & (1 << 5)) && gp->reg.cur_line < SCREEN_HEIGHT)
					interrupts_raise(ir, IRQ_LCD);

				GPU_SET_MODE(gp, GPU_SCAN_OAM);
			}
		}
		break;
	case GPU_VERT_BLANK:
		if (gp->state_start_clock >= GPU_VERT_BLANK_TIMING) {
			gp->state_start_clock = 0;
			gp->reg.cur_line++;

			if (gp->reg.cur_line > SCREEN_HEIGHT + 10) {
				GPU_SET_MODE(gp, GPU_HORIZ_BLANK);
				gp->reg.cur_line = 0;
				gpu_render(gp);
			}
		}
		break;
	case GPU_SCAN_OAM:
		if (gp->state_start_clock >= GPU_SCAN_OAM_TIMING) {
			gp->state_start_clock = 0;
			GPU_SET_MODE(gp, GPU_SCAN_VRAM);
		}
		break;
	case GPU_SCAN_VRAM:
		if (gp->state_start_clock >= GPU_SCAN_VRAM_TIMING) {
			if ((gp->reg.status & (1 << 3)) && gp->reg.cur_line < SCREEN_HEIGHT)
				interrupts_raise(ir, IRQ_LCD);

			gp->state_start_clock = 0;
			GPU_SET_MODE(gp, GPU_HORIZ_BLANK);

			// Render one line
			if (gp->reg.cur_line < SCREEN_HEIGHT)
				gpu_render(gp);
		}
		break;
	}

	// Check LY == LYC
	if (gp->reg.cur_line == gp->reg.check_line) {
		gp->reg.status |= (1 << 2);
		if (gp->reg.status & (1 << 6))
			interrupts_raise(ir, IRQ_LCD);
	} else {
		gp->reg.status &= ~(1 << 2);
	}
}