2024-04-21 12:37:45 -03:00
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "timer.h"
|
|
|
|
|
#include "../log.h"
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
#define T0_COUNTER timer->timer[0].counter
|
|
|
|
|
#define T0_SYNC_EN timer->timer[0].sync_enable
|
|
|
|
|
#define T0_SYNC_MODE timer->timer[0].sync_mode
|
|
|
|
|
#define T0_RESET_TGT timer->timer[0].reset_target
|
|
|
|
|
#define T0_IRQ_TGT timer->timer[0].irq_target
|
|
|
|
|
#define T0_IRQ_MAX timer->timer[0].irq_max
|
|
|
|
|
#define T0_IRQ_REPEAT timer->timer[0].irq_repeat
|
|
|
|
|
#define T0_IRQ_TOGGLE timer->timer[0].irq_toggle
|
|
|
|
|
#define T0_CLKSRC timer->timer[0].clk_source
|
|
|
|
|
#define T0_IRQ timer->timer[0].irq
|
|
|
|
|
#define T0_TGT_REACHED timer->timer[0].target_reached
|
|
|
|
|
#define T0_MAX_REACHED timer->timer[0].max_reached
|
|
|
|
|
#define T0_IRQ_FIRED timer->timer[0].irq_fired
|
|
|
|
|
#define T0_PAUSED timer->timer[0].paused
|
|
|
|
|
#define T0_BLANK_ONCE timer->timer[0].blank_once
|
|
|
|
|
#define T1_COUNTER timer->timer[1].counter
|
|
|
|
|
#define T1_SYNC_EN timer->timer[1].sync_enable
|
|
|
|
|
#define T1_SYNC_MODE timer->timer[1].sync_mode
|
|
|
|
|
#define T1_RESET_TGT timer->timer[1].reset_target
|
|
|
|
|
#define T1_IRQ_TGT timer->timer[1].irq_target
|
|
|
|
|
#define T1_IRQ_MAX timer->timer[1].irq_max
|
|
|
|
|
#define T1_IRQ_REPEAT timer->timer[1].irq_repeat
|
|
|
|
|
#define T1_IRQ_TOGGLE timer->timer[1].irq_toggle
|
|
|
|
|
#define T1_CLKSRC timer->timer[1].clk_source
|
|
|
|
|
#define T1_IRQ timer->timer[1].irq
|
|
|
|
|
#define T1_TGT_REACHED timer->timer[1].target_reached
|
|
|
|
|
#define T1_MAX_REACHED timer->timer[1].max_reached
|
|
|
|
|
#define T1_IRQ_FIRED timer->timer[1].irq_fired
|
|
|
|
|
#define T1_PAUSED timer->timer[1].paused
|
|
|
|
|
#define T1_BLANK_ONCE timer->timer[1].blank_once
|
|
|
|
|
#define T2_COUNTER timer->timer[2].counter
|
|
|
|
|
#define T2_SYNC_EN timer->timer[2].sync_enable
|
|
|
|
|
#define T2_SYNC_MODE timer->timer[2].sync_mode
|
|
|
|
|
#define T2_RESET_TGT timer->timer[2].reset_target
|
|
|
|
|
#define T2_IRQ_TGT timer->timer[2].irq_target
|
|
|
|
|
#define T2_IRQ_MAX timer->timer[2].irq_max
|
|
|
|
|
#define T2_IRQ_REPEAT timer->timer[2].irq_repeat
|
|
|
|
|
#define T2_IRQ_TOGGLE timer->timer[2].irq_toggle
|
|
|
|
|
#define T2_CLKSRC timer->timer[2].clk_source
|
|
|
|
|
#define T2_IRQ timer->timer[2].irq
|
|
|
|
|
#define T2_TGT_REACHED timer->timer[2].target_reached
|
|
|
|
|
#define T2_MAX_REACHED timer->timer[2].max_reached
|
|
|
|
|
#define T2_IRQ_FIRED timer->timer[2].irq_fired
|
|
|
|
|
#define T2_PAUSED timer->timer[2].paused
|
|
|
|
|
#define T2_BLANK_ONCE timer->timer[2].blank_once
|
|
|
|
|
#define T2_DIV_COUNTER timer->timer[2].div_counter
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
uint16_t timer_get_mode(psx_timer_t* timer, int index) {
|
|
|
|
|
uint16_t value = (timer->timer[index].sync_enable << 0) |
|
|
|
|
|
(timer->timer[index].sync_mode << 1) |
|
|
|
|
|
(timer->timer[index].reset_target << 3) |
|
|
|
|
|
(timer->timer[index].irq_target << 4) |
|
|
|
|
|
(timer->timer[index].irq_max << 5) |
|
|
|
|
|
(timer->timer[index].irq_repeat << 6) |
|
|
|
|
|
(timer->timer[index].irq_toggle << 7) |
|
|
|
|
|
(timer->timer[index].clk_source << 8) |
|
|
|
|
|
(timer->timer[index].irq << 10) |
|
|
|
|
|
(timer->timer[index].target_reached << 11) |
|
|
|
|
|
(timer->timer[index].max_reached << 12);
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->timer[index].target_reached = 0;
|
|
|
|
|
timer->timer[index].max_reached = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
return value;
|
|
|
|
|
}
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
void timer_set_mode(psx_timer_t* timer, int index, uint16_t value) {
|
|
|
|
|
timer->timer[index].sync_enable = (value >> 0) & 1;
|
|
|
|
|
timer->timer[index].sync_mode = (value >> 1) & 3;
|
|
|
|
|
timer->timer[index].reset_target = (value >> 3) & 1;
|
|
|
|
|
timer->timer[index].irq_target = (value >> 4) & 1;
|
|
|
|
|
timer->timer[index].irq_max = (value >> 5) & 1;
|
|
|
|
|
timer->timer[index].irq_repeat = (value >> 6) & 1;
|
|
|
|
|
timer->timer[index].irq_toggle = (value >> 7) & 1;
|
|
|
|
|
timer->timer[index].clk_source = (value >> 8) & 3;
|
|
|
|
|
timer->timer[index].target_reached = 0;
|
|
|
|
|
timer->timer[index].max_reached = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
// IRQ and counter are set to 0 on mode writes
|
|
|
|
|
timer->timer[index].irq = 1;
|
|
|
|
|
timer->timer[index].irq_fired = 0;
|
|
|
|
|
timer->timer[index].counter = 0;
|
|
|
|
|
timer->timer[index].div_counter = 0;
|
|
|
|
|
timer->timer[index].blank_once = 0;
|
|
|
|
|
timer->timer[index].paused = 0;
|
|
|
|
|
|
2024-06-03 00:35:56 -03:00
|
|
|
// printf(
|
|
|
|
|
// "timer_set_mode %u %04x\n"
|
|
|
|
|
// "sync_enable %u\n"
|
|
|
|
|
// "sync_mode %u\n"
|
|
|
|
|
// "reset_target %u\n"
|
|
|
|
|
// "irq_target %u\n"
|
|
|
|
|
// "irq_max %u\n"
|
|
|
|
|
// "irq_repeat %u\n"
|
|
|
|
|
// "irq_toggle %u\n"
|
|
|
|
|
// "clk_source %u\n"
|
|
|
|
|
// "target_reached %u\n"
|
|
|
|
|
// "max_reached %u\n"
|
|
|
|
|
// "target %04x\n",
|
|
|
|
|
// index, value,
|
|
|
|
|
// timer->timer[index].sync_enable,
|
|
|
|
|
// timer->timer[index].sync_mode,
|
|
|
|
|
// timer->timer[index].reset_target,
|
|
|
|
|
// timer->timer[index].irq_target,
|
|
|
|
|
// timer->timer[index].irq_max,
|
|
|
|
|
// timer->timer[index].irq_repeat,
|
|
|
|
|
// timer->timer[index].irq_toggle,
|
|
|
|
|
// timer->timer[index].clk_source,
|
|
|
|
|
// timer->timer[index].target_reached,
|
|
|
|
|
// timer->timer[index].max_reached,
|
|
|
|
|
// timer->timer[index].target
|
|
|
|
|
// );
|
2024-05-21 14:04:03 -03:00
|
|
|
|
|
|
|
|
switch (index) {
|
|
|
|
|
case 0: {
|
|
|
|
|
if ((T0_SYNC_MODE == 1) || (T0_SYNC_MODE == 2) || !T0_SYNC_EN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
T0_PAUSED = timer->hblank | (T0_SYNC_MODE == 3);
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case 1: {
|
|
|
|
|
if ((T1_SYNC_MODE == 1) || (T1_SYNC_MODE == 2) || !T1_SYNC_EN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
T1_PAUSED = timer->vblank | (T1_SYNC_MODE == 3);
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case 2: {
|
|
|
|
|
if (!T2_SYNC_EN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
T2_PAUSED = (T2_SYNC_MODE == 0) || (T2_SYNC_MODE == 3);
|
|
|
|
|
} break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-21 12:37:45 -03:00
|
|
|
|
|
|
|
|
const char* g_psx_timer_reg_names[] = {
|
|
|
|
|
"counter", 0, 0, 0,
|
|
|
|
|
"mode", 0, 0, 0,
|
|
|
|
|
"target", 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-11 12:04:09 -03:00
|
|
|
psx_timer_t* psx_timer_create(void) {
|
2024-04-21 12:37:45 -03:00
|
|
|
return (psx_timer_t*)malloc(sizeof(psx_timer_t));
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
void psx_timer_init(psx_timer_t* timer, psx_ic_t* ic, psx_gpu_t* gpu) {
|
2024-04-21 12:37:45 -03:00
|
|
|
memset(timer, 0, sizeof(psx_timer_t));
|
|
|
|
|
|
|
|
|
|
timer->io_base = PSX_TIMER_BEGIN;
|
|
|
|
|
timer->io_size = PSX_TIMER_SIZE;
|
|
|
|
|
|
|
|
|
|
timer->ic = ic;
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->gpu = gpu;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t psx_timer_read32(psx_timer_t* timer, uint32_t offset) {
|
|
|
|
|
int index = offset >> 4;
|
|
|
|
|
int reg = offset & 0xf;
|
|
|
|
|
|
|
|
|
|
switch (reg) {
|
2024-05-21 14:04:03 -03:00
|
|
|
case 0: return timer->timer[index].counter;
|
|
|
|
|
case 4: return timer_get_mode(timer, index);
|
2024-04-21 12:37:45 -03:00
|
|
|
case 8: return timer->timer[index].target;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
printf("Unhandled 32-bit TIMER read at offset %08x\n", offset);
|
2024-04-21 12:37:45 -03:00
|
|
|
|
|
|
|
|
return 0x0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t psx_timer_read16(psx_timer_t* timer, uint32_t offset) {
|
|
|
|
|
int index = offset >> 4;
|
|
|
|
|
int reg = offset & 0xf;
|
|
|
|
|
|
|
|
|
|
switch (reg) {
|
|
|
|
|
case 0: return timer->timer[index].counter;
|
2024-05-21 14:04:03 -03:00
|
|
|
case 4: return timer_get_mode(timer, index);
|
2024-04-21 12:37:45 -03:00
|
|
|
case 8: return timer->timer[index].target;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("Unhandled 16-bit TIMER read at offset %08x\n", offset);
|
|
|
|
|
|
|
|
|
|
return 0x0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t psx_timer_read8(psx_timer_t* timer, uint32_t offset) {
|
|
|
|
|
printf("Unhandled 8-bit TIMER read at offset %08x\n", offset);
|
|
|
|
|
|
|
|
|
|
return 0x0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
void timer_handle_irq(psx_timer_t* timer, int i);
|
|
|
|
|
|
2024-04-21 12:37:45 -03:00
|
|
|
void psx_timer_write32(psx_timer_t* timer, uint32_t offset, uint32_t value) {
|
|
|
|
|
int index = offset >> 4;
|
|
|
|
|
int reg = offset & 0xf;
|
|
|
|
|
|
|
|
|
|
switch (reg) {
|
2024-05-21 14:04:03 -03:00
|
|
|
case 0: timer->timer[index].counter = value & 0xffff; break;
|
|
|
|
|
case 4: timer_set_mode(timer, index, value); break;
|
|
|
|
|
case 8: timer->timer[index].target = value & 0xffff; break;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer_handle_irq(timer, index);
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psx_timer_write16(psx_timer_t* timer, uint32_t offset, uint16_t value) {
|
|
|
|
|
int index = offset >> 4;
|
|
|
|
|
int reg = offset & 0xf;
|
|
|
|
|
|
|
|
|
|
switch (reg) {
|
2024-05-21 14:04:03 -03:00
|
|
|
case 0: timer->timer[index].counter = value & 0xffff; break;
|
|
|
|
|
case 4: timer_set_mode(timer, index, value); break;
|
|
|
|
|
case 8: timer->timer[index].target = value & 0xffff; break;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer_handle_irq(timer, index);
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psx_timer_write8(psx_timer_t* timer, uint32_t offset, uint8_t value) {
|
|
|
|
|
printf("Unhandled 8-bit TIMER write at offset %08x (%02x)\n", offset, value);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
void timer_handle_irq(psx_timer_t* timer, int i) {
|
|
|
|
|
int irq = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
int target_reached = timer->timer[i].counter > timer->timer[i].target;
|
|
|
|
|
int max_reached = timer->timer[i].counter > 65535.0f;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (target_reached) {
|
|
|
|
|
timer->timer[i].target_reached = 1;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-07-18 12:25:52 -03:00
|
|
|
// if ((i == 1) && (T1_CLKSRC == 1))
|
2024-06-03 00:35:56 -03:00
|
|
|
// printf("target %04x (%f) reached\n", timer->timer[i].target, timer->timer[i].counter);
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-06-03 00:35:56 -03:00
|
|
|
if (timer->timer[i].reset_target)
|
|
|
|
|
timer->timer[i].counter = 0;
|
|
|
|
|
|
|
|
|
|
if (timer->timer[i].irq_target)
|
2024-05-21 14:04:03 -03:00
|
|
|
irq = 1;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (max_reached) {
|
2024-07-18 12:25:52 -03:00
|
|
|
timer->timer[i].counter = 0;
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->timer[i].max_reached = 1;
|
|
|
|
|
|
2024-06-03 00:35:56 -03:00
|
|
|
if (timer->timer[i].irq_max)
|
2024-05-21 14:04:03 -03:00
|
|
|
irq = 1;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
2024-05-21 14:04:03 -03:00
|
|
|
|
|
|
|
|
if (!irq)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!timer->timer[i].irq_toggle) {
|
|
|
|
|
timer->timer[i].irq = 0;
|
|
|
|
|
} else {
|
|
|
|
|
timer->timer[i].irq ^= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int trigger = !timer->timer[i].irq;
|
|
|
|
|
|
|
|
|
|
if (!timer->timer[i].irq_repeat) {
|
|
|
|
|
if (trigger && !timer->timer[i].irq_fired) {
|
|
|
|
|
timer->timer[i].irq_fired = 1;
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer->timer[i].irq = 1;
|
|
|
|
|
|
|
|
|
|
if (trigger) {
|
|
|
|
|
psx_ic_irq(timer->ic, 16 << i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float timer_get_dotclock_div(psx_timer_t* timer) {
|
|
|
|
|
static const float dmode_dotclk_div_table[] = {
|
|
|
|
|
10.0f, 8.0f, 5.0f, 4.0f
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (timer->gpu->display_mode & 0x40) {
|
|
|
|
|
return 11.0f / 7.0f / 7.0f;
|
|
|
|
|
} else {
|
|
|
|
|
return 11.0f / 7.0f / dmode_dotclk_div_table[timer->gpu->display_mode & 0x3];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void timer_update_timer0(psx_timer_t* timer, int cyc) {
|
|
|
|
|
if (T0_PAUSED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (T0_CLKSRC & 1) {
|
|
|
|
|
// Dotclock test
|
|
|
|
|
T0_COUNTER += (float)cyc * timer_get_dotclock_div(timer);
|
|
|
|
|
} else {
|
|
|
|
|
T0_COUNTER += (float)cyc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer_handle_irq(timer, 0);
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void timer_update_timer1(psx_timer_t* timer, int cyc) {
|
2024-05-21 14:04:03 -03:00
|
|
|
if (T1_PAUSED)
|
|
|
|
|
return;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (T1_CLKSRC & 1) {
|
|
|
|
|
// Counter is incremented in our hblank callback
|
2024-04-21 12:37:45 -03:00
|
|
|
} else {
|
2024-05-21 14:04:03 -03:00
|
|
|
T1_COUNTER += (float)cyc;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer_handle_irq(timer, 1);
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void timer_update_timer2(psx_timer_t* timer, int cyc) {
|
2024-05-21 14:04:03 -03:00
|
|
|
if (T2_PAUSED)
|
|
|
|
|
return;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (T2_CLKSRC <= 1) {
|
2024-06-03 00:35:56 -03:00
|
|
|
T2_COUNTER += (float)cyc;
|
2024-05-21 14:04:03 -03:00
|
|
|
} else {
|
2024-06-03 00:35:56 -03:00
|
|
|
T2_COUNTER += ((float)cyc) / 8.0f;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer_handle_irq(timer, 2);
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psx_timer_update(psx_timer_t* timer, int cyc) {
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->prev_hblank = timer->hblank;
|
|
|
|
|
timer->prev_vblank = timer->vblank;
|
|
|
|
|
|
|
|
|
|
timer_update_timer0(timer, 2);
|
|
|
|
|
timer_update_timer1(timer, 2);
|
|
|
|
|
timer_update_timer2(timer, 2);
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {
|
|
|
|
|
psx_timer_t* timer = gpu->udata[1];
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->hblank = 1;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-06-03 00:35:56 -03:00
|
|
|
if ((T1_CLKSRC & 1) && !T1_PAUSED) {
|
2024-05-21 14:04:03 -03:00
|
|
|
++T1_COUNTER;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-06-03 00:35:56 -03:00
|
|
|
timer_handle_irq(timer, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (!T0_SYNC_EN)
|
|
|
|
|
return;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
switch (T0_SYNC_MODE) {
|
|
|
|
|
case 0: T0_PAUSED = 1; break;
|
|
|
|
|
case 1: T0_COUNTER = 0; break;
|
|
|
|
|
case 2: T0_COUNTER = 0; T0_PAUSED = 0; break;
|
|
|
|
|
case 3: {
|
|
|
|
|
if (!T0_BLANK_ONCE) {
|
|
|
|
|
T0_BLANK_ONCE = 1;
|
|
|
|
|
T0_SYNC_EN = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
T0_PAUSED = 0;
|
2024-05-21 14:04:03 -03:00
|
|
|
}
|
|
|
|
|
} break;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psxe_gpu_hblank_end_event_cb(psx_gpu_t* gpu) {
|
|
|
|
|
psx_timer_t* timer = gpu->udata[1];
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->hblank = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (!T0_SYNC_EN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (T0_SYNC_MODE) {
|
|
|
|
|
case 0: T0_PAUSED = 0; break;
|
|
|
|
|
case 2: T0_PAUSED = 1; break;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psxe_gpu_vblank_timer_event_cb(psx_gpu_t* gpu) {
|
|
|
|
|
psx_timer_t* timer = gpu->udata[1];
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->vblank = 1;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (!T1_SYNC_EN)
|
|
|
|
|
return;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
switch (T1_SYNC_MODE) {
|
|
|
|
|
case 0: T1_PAUSED = 1; break;
|
|
|
|
|
case 1: T1_COUNTER = 0; break;
|
|
|
|
|
case 2: T1_COUNTER = 0; T1_PAUSED = 0; break;
|
|
|
|
|
case 3: {
|
|
|
|
|
if (!T1_BLANK_ONCE) {
|
|
|
|
|
T1_BLANK_ONCE = 1;
|
|
|
|
|
T1_SYNC_EN = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
T1_PAUSED = 0;
|
2024-05-21 14:04:03 -03:00
|
|
|
}
|
|
|
|
|
} break;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psxe_gpu_vblank_end_event_cb(psx_gpu_t* gpu) {
|
|
|
|
|
psx_timer_t* timer = gpu->udata[1];
|
|
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
timer->vblank = 0;
|
2024-04-21 12:37:45 -03:00
|
|
|
|
2024-05-21 14:04:03 -03:00
|
|
|
if (!T1_SYNC_EN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (T1_SYNC_MODE) {
|
|
|
|
|
case 0: T1_PAUSED = 0; break;
|
|
|
|
|
case 2: T1_PAUSED = 1; break;
|
2024-04-21 12:37:45 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void psx_timer_destroy(psx_timer_t* timer) {
|
|
|
|
|
free(timer);
|
2023-06-09 22:25:47 -03:00
|
|
|
}
|