Skip to content

Commit

Permalink
Many fixes and improvements
Browse files Browse the repository at this point in the history
Fixed CD-XA popping issue
Improved SPU IRQ emulation
Fixed GPU signed draw offsets
Improved CDROM timings (better compatibility)
  • Loading branch information
allkern committed Jun 3, 2024
1 parent 7f9fc68 commit 594aa46
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 73 deletions.
4 changes: 3 additions & 1 deletion build-deps.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ if (Test-Path "SDL2-2.30.3") {
$SDL2_URL = "https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-devel-2.30.3-mingw.zip"

Invoke-WebRequest -URI $SDL2_URL -OutFile "sdl2.zip"
Expand-Archive "sdl2.zip" -DestinationPath "." -Force
Expand-Archive "sdl2.zip" -DestinationPath "." -Force

Remove-Item "sdl2.zip"
30 changes: 25 additions & 5 deletions psx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1477,15 +1477,23 @@ int32_t gte_clamp_mac(psx_cpu_t* cpu, int i, int64_t value) {
if (i == 3)
cpu->s_mac3 = value;

if (value < -0x80000000000) {
if (value < -0x80000000000ll) {
R_FLAG |= 0x8000000 >> (i - 1);
} else if (value > 0x7ffffffffff) {
} else if (value > 0x7ffffffffffll) {
R_FLAG |= 0x40000000 >> (i - 1);
}

return (int32_t)(((value << 20) >> 20) >> cpu->gte_sf);
}

void gte_check_mac(psx_cpu_t* cpu, int i, int64_t value) {
if (value < -0x80000000000ll) {
R_FLAG |= 0x8000000 >> (i - 1);
} else if (value > 0x7ffffffffffll) {
R_FLAG |= 0x40000000 >> (i - 1);
}
}

int32_t gte_clamp_ir0(psx_cpu_t* cpu, int32_t value) {
if (value < 0) {
R_FLAG |= 0x1000;
Expand Down Expand Up @@ -1841,9 +1849,21 @@ void psx_gte_i_invalid(psx_cpu_t* cpu) {
R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1)) + (I64(R_LR2) * I64(R_IR2)) + (I64(R_LR3) * I64(R_IR3))); \
R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1)) + (I64(R_LG2) * I64(R_IR2)) + (I64(R_LG3) * I64(R_IR3))); \
R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1)) + (I64(R_LB2) * I64(R_IR2)) + (I64(R_LB3) * I64(R_IR3))); \
gte_check_mac(cpu, 1, ((I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1)))); \
gte_check_mac(cpu, 2, ((I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1)))); \
gte_check_mac(cpu, 3, ((I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1)))); \
gte_check_mac(cpu, 1, I64(R_LR2) * I64(R_IR2)); \
gte_check_mac(cpu, 2, I64(R_LG2) * I64(R_IR2)); \
gte_check_mac(cpu, 3, I64(R_LB2) * I64(R_IR2)); \
gte_check_mac(cpu, 1, I64(R_LR3) * I64(R_IR3)); \
gte_check_mac(cpu, 2, I64(R_LG3) * I64(R_IR3)); \
gte_check_mac(cpu, 3, I64(R_LB3) * I64(R_IR3)); \
R_MAC1 = gte_clamp_mac(cpu, 1, ((I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2)) + (I64(R_LR3) * I64(R_IR3))); \
R_MAC2 = gte_clamp_mac(cpu, 2, ((I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2)) + (I64(R_LG3) * I64(R_IR3))); \
R_MAC3 = gte_clamp_mac(cpu, 3, ((I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2)) + (I64(R_LB3) * I64(R_IR3))); \
/* R_MAC1 = gte_clamp_mac(cpu, 1, () + () + ()); */ \
/* R_MAC2 = gte_clamp_mac(cpu, 2, () + () + ()); */ \
/* R_MAC3 = gte_clamp_mac(cpu, 3, () + () + ()); */ \
R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
Expand Down
63 changes: 34 additions & 29 deletions psx/dev/cdrom.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ void cdrom_cmd_getstat(psx_cdrom_t* cdrom) {
return;
}

cdrom->irq_delay = DELAY_1MS;
cdrom->irq_delay = DELAY_1MS * 2;
cdrom->state = CD_STATE_SEND_RESP1;
cdrom->delayed_command = CDL_GETSTAT;
} break;
Expand All @@ -262,7 +262,7 @@ void cdrom_cmd_getstat(psx_cdrom_t* cdrom) {
SET_BITS(ifr, IFR_INT, IFR_INT3);
RESP_PUSH(
GETSTAT_MOTOR |
((cdrom->cdda_playing || cdrom->xa_playing) ? GETSTAT_PLAY : 0) |
(cdrom->cdda_playing ? GETSTAT_PLAY : 0) |
(cdrom->ongoing_read_command ? GETSTAT_READ : 0) |
(cdrom->disc ? 0 : GETSTAT_TRAYOPEN)
);
Expand All @@ -271,7 +271,7 @@ void cdrom_cmd_getstat(psx_cdrom_t* cdrom) {
// printf("getstat command=%02x\n", cdrom->ongoing_read_command);
cdrom->state = CD_STATE_SEND_RESP2;
cdrom->delayed_command = cdrom->ongoing_read_command;
cdrom->irq_delay = DELAY_1MS;
cdrom->irq_delay = DELAY_1MS * 2;
} else {
cdrom->delayed_command = CDL_NONE;
cdrom->state = CD_STATE_RECV_CMD;
Expand Down Expand Up @@ -379,15 +379,15 @@ void cdrom_cmd_play(psx_cdrom_t* cdrom) {
case CD_STATE_RECV_CMD: {
int track = 0;

if (cdrom->cdda_playing) {
cdrom->pfifo_index = 0;
// if (cdrom->cdda_playing) {
// cdrom->pfifo_index = 0;

cdrom->irq_delay = DELAY_1MS;
cdrom->state = CD_STATE_SEND_RESP1;
cdrom->delayed_command = CDL_PLAY;
// cdrom->irq_delay = DELAY_1MS;
// cdrom->state = CD_STATE_SEND_RESP1;
// cdrom->delayed_command = CDL_PLAY;

return;
}
// return;
// }

// Optional track number parameter
if (cdrom->pfifo_index)
Expand Down Expand Up @@ -461,6 +461,7 @@ void cdrom_cmd_readn(psx_cdrom_t* cdrom) {

if (cdrom->mode & MODE_XA_ADPCM) {
cdrom->xa_msf = cdrom->seek_msf;
cdrom->xa_current_msf = cdrom->xa_msf;
cdrom->xa_playing = 1;
cdrom->xa_remaining_samples = 0;

Expand Down Expand Up @@ -883,7 +884,7 @@ void cdrom_cmd_getparam(psx_cdrom_t* cdrom) {
void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) {
switch (cdrom->state) {
case CD_STATE_RECV_CMD: {
cdrom->irq_delay = DELAY_1MS;
cdrom->irq_delay = DELAY_1MS * 4;
cdrom->delayed_command = CDL_GETLOCL;
cdrom->state = CD_STATE_SEND_RESP1;
} break;
Expand All @@ -903,7 +904,7 @@ void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) {
// printf("command=%02x\n", cdrom->ongoing_read_command);
cdrom->state = CD_STATE_SEND_RESP2;
cdrom->delayed_command = cdrom->ongoing_read_command;
cdrom->irq_delay = DELAY_1MS;
cdrom->irq_delay = DELAY_1MS * 4;
} else {
cdrom->delayed_command = CDL_NONE;
cdrom->state = CD_STATE_RECV_CMD;
Expand All @@ -914,7 +915,7 @@ void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) {
void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) {
switch (cdrom->state) {
case CD_STATE_RECV_CMD: {
cdrom->irq_delay = DELAY_1MS;
cdrom->irq_delay = DELAY_1MS * 8;
cdrom->delayed_command = CDL_GETLOCP;
cdrom->state = CD_STATE_SEND_RESP1;
} break;
Expand Down Expand Up @@ -968,7 +969,7 @@ void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) {
printf("getlocp command=%02x\n", cdrom->ongoing_read_command);
cdrom->state = CD_STATE_SEND_RESP2;
cdrom->delayed_command = cdrom->ongoing_read_command;
cdrom->irq_delay = DELAY_1MS;
cdrom->irq_delay = DELAY_1MS * 8;
} else {
cdrom->delayed_command = CDL_NONE;
cdrom->state = CD_STATE_RECV_CMD;
Expand Down Expand Up @@ -1234,10 +1235,10 @@ void cdrom_cmd_test(psx_cdrom_t* cdrom) {

// 95h,05h,16h,C1h
SET_BITS(ifr, IFR_INT, IFR_INT3);
RESP_PUSH(0xc1);
RESP_PUSH(0x16);
RESP_PUSH(0x05);
RESP_PUSH(0x95);
RESP_PUSH(0xc0);
RESP_PUSH(0x19);
RESP_PUSH(0x09);
RESP_PUSH(0x94);

cdrom->state = CD_STATE_RECV_CMD;
} break;
Expand Down Expand Up @@ -1327,6 +1328,7 @@ void cdrom_cmd_reads(psx_cdrom_t* cdrom) {

if (cdrom->mode & MODE_XA_ADPCM) {
cdrom->xa_msf = cdrom->seek_msf;
cdrom->xa_current_msf = cdrom->xa_msf;
cdrom->xa_playing = 1;
cdrom->xa_remaining_samples = 0;

Expand Down Expand Up @@ -2086,8 +2088,6 @@ void cdrom_decode_xa_sector(psx_cdrom_t* cdrom, void* buf) {

int16_t left[28];
int16_t right[28];
int16_t left_h[2] = { 0, 0 };
int16_t right_h[2] = { 0, 0 };

int16_t* left_ptr = cdrom->xa_left_buf;
int16_t* right_ptr = cdrom->xa_right_buf;
Expand All @@ -2096,20 +2096,20 @@ void cdrom_decode_xa_sector(psx_cdrom_t* cdrom, void* buf) {
for (int i = 0; i < 18; i++) {
for (int blk = 0; blk < 4; blk++) {
if (cdrom->xa_sector_buf[0x13] & 1) {
cdrom_decode_xa_block(cdrom, src, blk, 0, left, left_h);
cdrom_decode_xa_block(cdrom, src, blk, 1, right, right_h);
cdrom_decode_xa_block(cdrom, src, blk, 0, left, cdrom->xa_left_h);
cdrom_decode_xa_block(cdrom, src, blk, 1, right, cdrom->xa_right_h);

for (int i = 0; i < 28; i++) {
*left_ptr++ = left[i];
*right_ptr++ = right[i];
}
} else {
cdrom_decode_xa_block(cdrom, src, blk, 0, left, left_h);
cdrom_decode_xa_block(cdrom, src, blk, 0, left, cdrom->xa_left_h);

for (int i = 0; i < 28; i++)
*mono_ptr++ = left[i];

cdrom_decode_xa_block(cdrom, src, blk, 1, left, left_h);
cdrom_decode_xa_block(cdrom, src, blk, 1, left, cdrom->xa_left_h);

for (int i = 0; i < 28; i++)
*mono_ptr++ = left[i];
Expand All @@ -2124,6 +2124,7 @@ void cdrom_fetch_xa_sector(psx_cdrom_t* cdrom) {
while (true) {
if (psx_disc_seek(cdrom->disc, cdrom->xa_msf)) {
cdrom->xa_playing = 0;
cdrom->xa_remaining_samples = 0;

return;
}
Expand All @@ -2132,12 +2133,12 @@ void cdrom_fetch_xa_sector(psx_cdrom_t* cdrom) {

msf_add_f(&cdrom->xa_msf, 1);

// Check for EOR, EOF bits
if (cdrom->xa_sector_buf[0x12] & 0x80)
// Check for EOR bit
if (cdrom->xa_sector_buf[0x12] & 1)
return;

// Check RT and Audio bit
if ((cdrom->xa_sector_buf[0x12] & 4) != 4)
// Check Audio bit
if (!(cdrom->xa_sector_buf[0x12] & 4))
continue;

// If we get here it means this is a real-time audio sector.
Expand Down Expand Up @@ -2185,15 +2186,19 @@ void psx_cdrom_get_cdda_samples(psx_cdrom_t* cdrom, void* buf, int size, psx_spu
if (!cdrom->xa_remaining_samples) {
cdrom_fetch_xa_sector(cdrom);

if (cdrom->xa_sector_buf[0x12] & 0x80) {
if (cdrom->xa_sector_buf[0x12] & 0x01) {
SET_BITS(status, STAT_ADPBUSY_MASK, 0);

printf("Pausing XA-ADPCM playback\n");

cdrom->xa_playing = 0;
cdrom->xa_remaining_samples = 0;

return;
}

msf_add_f(&cdrom->xa_current_msf, 1);

stereo = (cdrom->xa_sector_buf[0x13] & 1) == 1;

cdrom_decode_xa_sector(cdrom, buf);
Expand Down
7 changes: 5 additions & 2 deletions psx/dev/cdrom.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
#include "../msf.h"
#include "spu.h"

// #define DELAY_1MS (0xc4e1)
#define DELAY_1MS (0xc4e1)
// #define READ_SINGLE_DELAY (0x6e1cd)
// #define READ_DOUBLE_DELAY (0x36cd2)
#define DELAY_1MS (PSX_CPU_CPS / 1000)
// #define DELAY_1MS (PSX_CPU_CPS / 1000)
#define READ_SINGLE_DELAY (PSX_CPU_CPS / 75)
#define READ_DOUBLE_DELAY (PSX_CPU_CPS / (2 * 75))

Expand Down Expand Up @@ -210,11 +210,14 @@ typedef struct {
// XA-ADPCM
uint8_t* xa_sector_buf;
msf_t xa_msf;
msf_t xa_current_msf;
int xa_playing;
int xa_mute;
uint8_t xa_file;
uint8_t xa_channel;
uint8_t xa_coding;
int16_t xa_left_h[2];
int16_t xa_right_h[2];
int16_t* xa_left_buf;
int16_t* xa_right_buf;
int16_t* xa_mono_buf;
Expand Down
8 changes: 2 additions & 6 deletions psx/dev/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,14 +345,10 @@ void psx_dma_do_cdrom(psx_dma_t* dma) {

uint32_t size = BCR_SIZE(cdrom);

if (!size) {
if (!size)
printf("0 sized CDROM DMA\n");

return;
exit(1);
}

dma->cdrom_irq_delay = size * 24;
dma->cdrom_irq_delay = 1;

if (!CHCR_TDIR(cdrom)) {
for (int i = 0; i < size; i++) {
Expand Down
17 changes: 9 additions & 8 deletions psx/dev/gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,8 @@ void gpu_render_textured_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vert
}
}

#define I32(v, b) (((int32_t)((v) << (31-b))) >> (31-b))

void gpu_rect(psx_gpu_t* gpu) {
switch (gpu->state) {
case GPU_STATE_RECV_CMD: {
Expand Down Expand Up @@ -1516,8 +1518,8 @@ void gpu_cmd_02(psx_gpu_t* gpu) {
// gpu->ysiz
// );

for (uint32_t y = gpu->v0.y; y < (gpu->v0.y + gpu->ysiz); y++) {
for (uint32_t x = gpu->v0.x; x < (gpu->v0.x + gpu->xsiz); x++) {
for (int y = gpu->v0.y; y < (gpu->v0.y + gpu->ysiz); y++) {
for (int x = gpu->v0.x; x < (gpu->v0.x + gpu->xsiz); x++) {
// This shouldn't be needed
int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
(y >= gpu->draw_y1) && (y <= gpu->draw_y2);
Expand Down Expand Up @@ -1645,8 +1647,8 @@ void psx_gpu_update_cmd(psx_gpu_t* gpu) {
gpu->draw_y2 = (gpu->buf[0] >> 10) & 0x1ff;
} break;
case 0xe5: {
gpu->off_x = (gpu->buf[0] >> 0 ) & 0x7ff;
gpu->off_y = (gpu->buf[0] >> 11) & 0x7ff;
gpu->off_x = ((int32_t)((gpu->buf[0] >> 0 ) & 0x7ff) << 21) >> 21;
gpu->off_y = ((int32_t)((gpu->buf[0] >> 11) & 0x7ff) << 21) >> 21;
} break;
case 0xe6: {
/* To-do: Implement mask bit thing */
Expand Down Expand Up @@ -1791,8 +1793,9 @@ void gpu_hblank_event(psx_gpu_t* gpu) {
// Player Select. It probably uses T2 IRQs to time
// GetlocP commands, if the timer is too slow it will
// break.
if (!(gpu->line & 7))
psx_ic_irq(gpu->ic, IC_TIMER2);
// if (!(gpu->line & 7))
// psx_ic_irq(gpu->ic, IC_TIMER2);
// psx_ic_irq(gpu->ic, IC_SPU);
} else {
gpu->gpustat &= ~(1 << 31);
}
Expand All @@ -1808,8 +1811,6 @@ void gpu_hblank_event(psx_gpu_t* gpu) {
if (gpu->event_cb_table[GPU_EVENT_VBLANK_END])
gpu->event_cb_table[GPU_EVENT_VBLANK_END](gpu);

psx_ic_irq(gpu->ic, IC_SPU);

gpu->line = 0;
}
}
Expand Down
2 changes: 1 addition & 1 deletion psx/dev/gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct psx_gpu_t {
uint32_t draw_x2, draw_y2;

// Drawing offset
uint32_t off_x, off_y;
int32_t off_x, off_y;

// Texture Window
uint32_t texw_mx, texw_my;
Expand Down
10 changes: 9 additions & 1 deletion psx/dev/spu.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,13 @@ psx_spu_t* psx_spu_create(void) {
return (psx_spu_t*)malloc(sizeof(psx_spu_t));
}

void psx_spu_init(psx_spu_t* spu) {
void psx_spu_init(psx_spu_t* spu, psx_ic_t* ic) {
memset(spu, 0, sizeof(psx_spu_t));

spu->io_base = PSX_SPU_BEGIN;
spu->io_size = PSX_SPU_SIZE;

spu->ic = ic;
spu->ram = (uint8_t*)malloc(SPU_RAM_SIZE);

memset(spu->ram, 0, SPU_RAM_SIZE);
Expand Down Expand Up @@ -141,6 +142,9 @@ void spu_read_block(psx_spu_t* spu, int v) {
int32_t f0 = g_spu_pos_adpcm_table[filter];
int32_t f1 = g_spu_neg_adpcm_table[filter];

if ((spu->irq9addr << 3) == addr)
psx_ic_irq(spu->ic, IC_SPU);

for (int j = 0; j < 28; j++) {
uint16_t n = (spu->ram[addr + 2 + (j >> 1)] >> ((j & 1) * 4)) & 0xf;

Expand Down Expand Up @@ -357,6 +361,10 @@ int spu_handle_write(psx_spu_t* spu, uint32_t offset, uint32_t value) {
spu_kon(spu, value << (16 * high));
} return 1;

// case SPUR_SPUIRQA: {
// spu->irq9addr = value << 3;
// } return 1;

case SPUR_KOFFL: case SPUR_KOFFH: {
int high = (offset & 2) != 0;

Expand Down
Loading

0 comments on commit 594aa46

Please sign in to comment.