ref: beff879e24af96a354b1170d38a2e396092020e1
parent: df3292dd771872c3f00b3bbaa4c3ae564fc6e5bb
author: allkern <lisandroaalarcon@gmail.com>
date: Sun Jul 16 19:19:05 EDT 2023
Implement most timer logic
--- a/psx/dev/gpu.h
+++ b/psx/dev/gpu.h
@@ -28,7 +28,8 @@
GPU_EVENT_VBLANK,
GPU_EVENT_VBLANK_END,
GPU_EVENT_HBLANK,
- GPU_EVENT_HBLANK_END
+ GPU_EVENT_HBLANK_END,
+ GPU_EVENT_VBLANK_TIMER
};
enum {--- a/psx/dev/ic.h
+++ b/psx/dev/ic.h
@@ -29,9 +29,9 @@
IC_GPU = 0x002,
IC_CDROM = 0x004,
IC_DMA = 0x008,
- IC_TMR0 = 0x010,
- IC_TMR1 = 0x020,
- IC_TMR2 = 0x040,
+ IC_TIMER0 = 0x010,
+ IC_TIMER1 = 0x020,
+ IC_TIMER2 = 0x040,
IC_JOY = 0x080,
IC_SIO = 0x100,
IC_SPU = 0x200,
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -10,16 +10,21 @@
#define T0_MODE timer->timer[0].mode
#define T0_TARGET timer->timer[0].target
#define T0_PAUSED timer->timer[0].paused
+#define T0_IRQ_FIRED timer->timer[0].irq_fired
+
#define T1_COUNTER timer->timer[1].counter
#define T1_PREV timer->timer[1].prev_counter
#define T1_MODE timer->timer[1].mode
#define T1_TARGET timer->timer[1].target
#define T1_PAUSED timer->timer[1].paused
+#define T1_IRQ_FIRED timer->timer[1].irq_fired
+
#define T2_COUNTER timer->timer[2].counter
#define T2_PREV timer->timer[2].prev_counter
#define T2_MODE timer->timer[2].mode
#define T2_TARGET timer->timer[2].target
#define T2_PAUSED timer->timer[2].paused
+#define T2_IRQ_FIRED timer->timer[2].irq_fired
psx_timer_t* psx_timer_create() {return (psx_timer_t*)malloc(sizeof(psx_timer_t));
@@ -40,7 +45,11 @@
switch (reg) {case 0: return timer->timer[index].counter;
- case 4: return timer->timer[index].mode;
+ case 4: {+ timer->timer[index].mode &= 0xffffe7ff;
+
+ return timer->timer[index].mode;
+ } break;
case 8: return timer->timer[index].target;
}
@@ -55,7 +64,11 @@
switch (reg) {case 0: return timer->timer[index].counter;
- case 4: return timer->timer[index].mode;
+ case 4: {+ timer->timer[index].mode &= 0xffffe7ff;
+
+ return timer->timer[index].mode;
+ } break;
case 8: return timer->timer[index].target;
}
@@ -79,7 +92,11 @@
timer->timer[index].counter = value;
timer->f_counter[index] = value;
} return;
- case 4: timer->timer[index].mode = value; return;
+ case 4: {+ timer->timer[index].mode = value;
+ timer->timer[index].mode |= 0x400;
+ timer->timer[index].irq_fired = 0;
+ } return;
case 8: timer->timer[index].target = value; return;
}
@@ -95,7 +112,11 @@
timer->timer[index].counter = value;
timer->f_counter[index] = value;
} return;
- case 4: timer->timer[index].mode = value; return;
+ case 4: {+ timer->timer[index].mode = value;
+ timer->timer[index].mode |= 0x400;
+ timer->timer[index].irq_fired = 0;
+ } return;
case 8: timer->timer[index].target = value; return;
}
@@ -107,35 +128,90 @@
}
void timer_update_timer0(psx_timer_t* timer, int cyc) {+ T0_PREV = T0_COUNTER;
+ // Dotclock unsupported
+ // if (T0_MODE & 0x100)
+
+ if (!T0_PAUSED)
+ T0_COUNTER += cyc;
+
+ int can_fire_irq = (T0_MODE & MODE_IRQRMD) || !T0_IRQ_FIRED;
+
+ int reached_target = (T0_PREV <= T0_TARGET) && (T0_COUNTER >= T0_TARGET);
+ int reached_max = (T0_PREV <= 0xffff) && (T0_COUNTER >= 0xffff);
+
+ int target_irq = reached_target && (T0_MODE & MODE_TGTIRQ);
+ int max_irq = reached_max && (T0_MODE & MODE_MAXIRQ);
+
+ T0_MODE &= ~0x0800;
+ T0_MODE |= reached_target << 11;
+
+ T0_MODE &= ~0x1000;
+ T0_MODE |= reached_max << 12;
+
+ if ((target_irq || max_irq) && can_fire_irq) {+ if (T0_MODE & MODE_IRQPMD) {+ T0_MODE ^= 0x400;
+ } else {+ T0_MODE |= 0x400;
+ }
+
+ timer->timer[0].irq_fired = 1;
+
+ psx_ic_irq(timer->ic, IC_TIMER0);
+ }
+
+ if (T0_MODE & MODE_RESETC) {+ if (reached_target)
+ T0_COUNTER -= T0_TARGET;
+ } else {+ T0_COUNTER -= 0xffff;
+ }
}
void timer_update_timer1(psx_timer_t* timer, int cyc) {- int src = T1_MODE & 0x100;
-
T1_PREV = T1_COUNTER;
- if (!T1_PAUSED)
+ // Hblank increment is done in handler
+ if ((!T1_PAUSED) && !(T1_MODE & 0x100))
T1_COUNTER += cyc;
- uint16_t reset = (T1_MODE & MODE_RESETC) ? T1_TARGET : 0xffff;
+ int can_fire_irq = (T1_MODE & MODE_IRQRMD) || !T1_IRQ_FIRED;
- if ((T1_COUNTER >= reset) && (T1_PREV <= reset)) {- T1_COUNTER -= reset;
- T1_MODE |= 0x800;
+ int reached_target = (T1_PREV <= T1_TARGET) && (T1_COUNTER >= T1_TARGET);
+ int reached_max = (T1_PREV <= 0xffff) && (T1_COUNTER >= 0xffff);
- if (reset == 0xffff)
- T1_MODE |= 0x1000;
+ int target_irq = reached_target && (T1_MODE & MODE_TGTIRQ);
+ int max_irq = reached_max && (T1_MODE & MODE_MAXIRQ);
+
+ T1_MODE &= ~0x0800;
+ T1_MODE |= reached_target << 11;
+
+ T1_MODE &= ~0x1000;
+ T1_MODE |= reached_max << 12;
+
+ if ((target_irq || max_irq) && can_fire_irq) {+ if (T1_MODE & MODE_IRQPMD) {+ T1_MODE ^= 0x400;
+ } else {+ T1_MODE |= 0x400;
+ }
+
+ timer->timer[0].irq_fired = 1;
+
+ psx_ic_irq(timer->ic, IC_TIMER0);
}
- if ((T1_COUNTER >= 0xffff) && (T1_PREV <= 0xffff)) {- T1_COUNTER &= 0xffff;
- T1_MODE |= 0x1000;
+ if (T1_MODE & MODE_RESETC) {+ if (reached_target)
+ T1_COUNTER -= T1_TARGET;
+ } else {+ T1_COUNTER -= 0xffff;
}
}
-void timer_update_timer2(psx_timer_t* timer, int cyc) {- int src = T2_MODE & 0x100;
+void timer_update_timer2(psx_timer_t* timer, int cyc) {T2_PREV = T2_COUNTER;
if (!T2_PAUSED)
@@ -166,6 +242,9 @@
void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {psx_timer_t* timer = gpu->udata[1];
+ if (T1_MODE & 0x100)
+ T1_COUNTER++;
+
if (T0_MODE & MODE_SYNCEN) { switch (T0_MODE & 6) { case 0: {@@ -204,7 +283,46 @@
}
}
-void psxe_gpu_vblank_end_event_cb(psx_gpu_t* gpu) {}+void psxe_gpu_vblank_timer_event_cb(psx_gpu_t* gpu) {+ psx_timer_t* timer = gpu->udata[1];
+
+ if (T1_MODE & MODE_SYNCEN) {+ switch (T1_MODE & 6) {+ case 0: {+ T1_PAUSED = 1;
+ } break;
+
+ case 2: {+ T1_COUNTER = 0;
+ } break;
+
+ case 4: {+ T1_COUNTER = 0;
+ T1_PAUSED = 0;
+ } break;
+
+ case 6: {+ T1_MODE &= ~MODE_SYNCEN;
+ } break;
+ }
+ }
+}
+
+void psxe_gpu_vblank_end_event_cb(psx_gpu_t* gpu) {+ psx_timer_t* timer = gpu->udata[1];
+
+ if (T1_MODE & MODE_SYNCEN) {+ switch (T1_MODE & 6) {+ case 0: {+ T1_PAUSED = 0;
+ } break;
+
+ case 4: {+ T1_PAUSED = 1;
+ } break;
+ }
+ }
+}
void psx_timer_destroy(psx_timer_t* timer) {free(timer);
--- a/psx/dev/timer.h
+++ b/psx/dev/timer.h
@@ -68,6 +68,7 @@
uint32_t mode;
uint32_t target;
int paused;
+ int irq_fired;
} timer[3];
float f_counter[3];
@@ -84,9 +85,10 @@
void psx_timer_update(psx_timer_t*, int);
void psx_timer_destroy(psx_timer_t*);
-// Hblank event handlers
+// GPU event handlers
void psxe_gpu_hblank_event_cb(psx_gpu_t*);
void psxe_gpu_hblank_end_event_cb(psx_gpu_t*);
+void psxe_gpu_vblank_timer_event_cb(psx_gpu_t*);
void psxe_gpu_vblank_end_event_cb(psx_gpu_t*);
#endif
\ No newline at end of file
--
⑨