diff --git a/psx/dev/cdrom.c b/psx/dev/cdrom.c index f88fec2..7aa06df 100644 --- a/psx/dev/cdrom.c +++ b/psx/dev/cdrom.c @@ -306,8 +306,58 @@ void cdrom_cmd_setmode(psx_cdrom_t* cdrom) { } void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) { log_fatal("getlocl: Unimplemented"); exit(1); } void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) { log_fatal("getlocp: Unimplemented"); exit(1); } -void cdrom_cmd_gettn(psx_cdrom_t* cdrom) { log_fatal("gettn: Unimplemented"); exit(1); } -void cdrom_cmd_gettd(psx_cdrom_t* cdrom) { log_fatal("gettd: Unimplemented"); exit(1); } +void cdrom_cmd_gettn(psx_cdrom_t* cdrom) { + switch (cdrom->state) { + case CD_STATE_CMD: { + if (cdrom->pfifo_index) { + log_fatal("CdlGetTN: Expected exactly 0 parameters"); + + return; + } + + cdrom->irq_delay = DELAY_1MS; + cdrom->delayed_command = CDL_GETTN; + cdrom->state = CD_STATE_RESP1; + } break; + + case CD_STATE_RESP1: { + SET_BITS(ifr, IFR_INT, IFR_INT3); + RESP_PUSH(0x14); + RESP_PUSH(0x01); + RESP_PUSH(cdrom->stat); + + cdrom->delayed_command = CDL_NONE; + cdrom->state = CD_STATE_CMD; + } break; + } +} +void cdrom_cmd_gettd(psx_cdrom_t* cdrom) { + switch (cdrom->state) { + case CD_STATE_CMD: { + if (cdrom->pfifo_index != 1) { + log_fatal("CdlGetTD: Expected exactly 0 parameters"); + + return; + } + + int track = PFIFO_POP; + + cdrom->irq_delay = DELAY_1MS; + cdrom->delayed_command = CDL_GETTD; + cdrom->state = CD_STATE_RESP1; + } break; + + case CD_STATE_RESP1: { + SET_BITS(ifr, IFR_INT, IFR_INT3); + RESP_PUSH(0x14); + RESP_PUSH(0x01); + RESP_PUSH(cdrom->stat); + + cdrom->delayed_command = CDL_NONE; + cdrom->state = CD_STATE_CMD; + } break; + } +} void cdrom_cmd_seekl(psx_cdrom_t* cdrom) { switch (cdrom->state) { case CD_STATE_CMD: { @@ -427,7 +477,58 @@ void cdrom_cmd_getid(psx_cdrom_t* cdrom) { } break; } } -void cdrom_cmd_reads(psx_cdrom_t* cdrom) { log_fatal("reads: Unimplemented"); exit(1); } +void cdrom_cmd_reads(psx_cdrom_t* cdrom) { + switch (cdrom->state) { + case CD_STATE_CMD: { + log_fatal("CdlReadS: CD_STATE_CMD"); + cdrom->irq_delay = DELAY_1MS; + cdrom->state = CD_STATE_RESP1; + cdrom->delayed_command = CDL_READS; + } break; + + case CD_STATE_RESP1: { + log_fatal("CdlReadS: CD_STATE_RESP1"); + + SET_BITS(ifr, IFR_INT, 3); + RESP_PUSH(GETSTAT_MOTOR); + + fseek(cdrom->disc, cdrom->seek_offset, 0); + + int double_speed = cdrom->mode & MODE_SPEED; + + cdrom->irq_delay = double_speed ? READ_DOUBLE_DELAY : READ_SINGLE_DELAY; + cdrom->state = CD_STATE_RESP2; + cdrom->delayed_command = CDL_READS; + + if (cdrom->spin_delay) { + cdrom->irq_delay += cdrom->spin_delay; + cdrom->spin_delay = 0; + } + } break; + + case CD_STATE_RESP2: { + log_fatal("CdlReadS: CD_STATE_RESP2"); + + SET_BITS(ifr, IFR_INT, 1); + RESP_PUSH(GETSTAT_MOTOR | GETSTAT_READ); + + log_fatal("Reading data from disc. offset=%02x:%02x:%02x (%08x, tellg=%08x)", + cdrom->seek_mm, cdrom->seek_ss, cdrom->seek_sect, + cdrom->seek_offset, ftell(cdrom->disc) + ); + + cdrom->dfifo_index = 0; + + fread(cdrom->dfifo, 1, CD_SECTOR_SIZE, cdrom->disc); + + int double_speed = cdrom->mode & MODE_SPEED; + + cdrom->irq_delay = double_speed ? READ_DOUBLE_DELAY : READ_SINGLE_DELAY; + cdrom->state = CD_STATE_CMD; + cdrom->delayed_command = CDL_NONE; + } break; + } +} void cdrom_cmd_readtoc(psx_cdrom_t* cdrom) { log_fatal("readtoc: Unimplemented"); exit(1); } typedef void (*cdrom_cmd_t)(psx_cdrom_t*); diff --git a/psx/dev/dma.c b/psx/dev/dma.c index d192f5a..79b907e 100644 --- a/psx/dev/dma.c +++ b/psx/dev/dma.c @@ -106,8 +106,11 @@ void psx_dma_write32(psx_dma_t* dma, uint32_t offset, uint32_t value) { dma->dicr &= ~(value & DICR_FLAGS); // Write other fields - dma->dicr &= DICR_FLAGS; + uint32_t flags = dma->dicr & DICR_FLAGS; + + dma->dicr &= ~DICR_FLAGS; dma->dicr |= value & (~DICR_FLAGS); + dma->dicr |= flags; } break; default: { @@ -122,7 +125,7 @@ void psx_dma_write16(psx_dma_t* dma, uint32_t offset, uint16_t value) { default: { log_fatal("Unhandled 16-bit DMA write at offset %08x (%04x)", offset, value); - exit(1); + //exit(1); } break; } } @@ -132,7 +135,7 @@ void psx_dma_write8(psx_dma_t* dma, uint32_t offset, uint8_t value) { default: { log_fatal("Unhandled 8-bit DMA write at offset %08x (%02x)", offset, value); - exit(1); + //exit(1); } break; } } @@ -152,6 +155,8 @@ void psx_dma_do_gpu_linked(psx_dma_t* dma) { uint32_t size = hdr >> 24; uint32_t addr = dma->gpu.madr; + int count = 0; + while (true) { while (size--) { addr = (addr + (CHCR_STEP(gpu) ? -4 : 4)) & 0x1ffffc; @@ -161,6 +166,8 @@ void psx_dma_do_gpu_linked(psx_dma_t* dma) { // Write to GP0 psx_bus_write32(dma->bus, 0x1f801810, cmd); + + dma->gpu_irq_delay++; } addr = hdr & 0xffffff; @@ -195,6 +202,8 @@ void psx_dma_do_gpu_request(psx_dma_t* dma) { dma->gpu.madr += CHCR_STEP(gpu) ? -4 : 4; } } + + dma->gpu_irq_delay = size; } void psx_dma_do_gpu_burst(psx_dma_t* dma) { @@ -249,7 +258,7 @@ void psx_dma_do_cdrom(psx_dma_t* dma) { (dma->dicr >> 24) & 0x7f ); - uint32_t size = BCR_SIZE(cdrom) * BCR_BCNT(cdrom); + uint32_t size = BCR_SIZE(cdrom); if (!size) { log_fatal("0 sized CDROM DMA"); @@ -310,23 +319,6 @@ void psx_dma_do_spu(psx_dma_t* dma) { } dma->spu_irq_delay = size * 4; - - if (!CHCR_TDIR(spu)) { - for (int i = 0; i < size; i++) { - uint32_t data = 0; - - data |= psx_bus_read8(dma->bus, 0x1f801802) << 0; - data |= psx_bus_read8(dma->bus, 0x1f801802) << 8; - data |= psx_bus_read8(dma->bus, 0x1f801802) << 16; - data |= psx_bus_read8(dma->bus, 0x1f801802) << 24; - - psx_bus_write32(dma->bus, dma->spu.madr, data); - - dma->spu.madr += CHCR_STEP(spu) ? -4 : 4; - } - } else { - log_fatal("Invalid SPU DMA transfer direction"); - } // Clear BCR and CHCR trigger and busy bits dma->spu.chcr = 0; @@ -358,6 +350,8 @@ void psx_dma_do_otc(psx_dma_t* dma) { dma->otc.madr -= 4; } + dma->otc_irq_delay = BCR_SIZE(otc); + // Clear BCR and CHCR trigger and busy bits dma->otc.chcr = 0; //dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK); @@ -366,25 +360,31 @@ void psx_dma_do_otc(psx_dma_t* dma) { void psx_dma_update(psx_dma_t* dma, int cyc) { if (dma->cdrom_irq_delay) { - dma->cdrom_irq_delay -= cyc; + if (dma->dicr & DICR_DMA3EN) + dma->dicr |= DICR_DMA3FL; - if (dma->cdrom_irq_delay <= 0) { - if (dma->dicr & DICR_DMA3EN) - dma->dicr |= DICR_DMA3FL; - - dma->cdrom_irq_delay = 0; - } + dma->cdrom_irq_delay = 0; } if (dma->spu_irq_delay) { - dma->spu_irq_delay -= cyc; + if (dma->dicr & DICR_DMA4EN) + dma->dicr |= DICR_DMA4FL; + + dma->spu_irq_delay = 0; + } - if (dma->spu_irq_delay <= 0) { - if (dma->dicr & DICR_DMA4EN) - dma->dicr |= DICR_DMA4FL; + if (dma->gpu_irq_delay) { + if (dma->dicr & DICR_DMA2EN) + dma->dicr |= DICR_DMA2FL; - dma->spu_irq_delay = 0; - } + dma->gpu_irq_delay = 0; + } + + if (dma->otc_irq_delay) { + if (dma->dicr & DICR_DMA6EN) + dma->dicr |= DICR_DMA6FL; + + dma->otc_irq_delay = 0; } int prev_irq_signal = (dma->dicr & DICR_IRQSI) != 0; diff --git a/psx/dev/dma.h b/psx/dev/dma.h index 298b8c4..783cf2e 100644 --- a/psx/dev/dma.h +++ b/psx/dev/dma.h @@ -32,6 +32,8 @@ typedef struct { int cdrom_irq_delay; int spu_irq_delay; + int gpu_irq_delay; + int otc_irq_delay; uint32_t dpcr; uint32_t dicr; diff --git a/psx/dev/gpu.c b/psx/dev/gpu.c index 60f7bc7..1051ec2 100644 --- a/psx/dev/gpu.c +++ b/psx/dev/gpu.c @@ -62,6 +62,25 @@ uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) { gpu->c0_tsiz -= 2; } + if (gpu->gp1_10h_req) { + switch (gpu->gp1_10h_req & 7) { + case 2: { + data = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8); + } break; + case 3: { + data = (gpu->draw_y1 << 10) | gpu->draw_x1; + } break; + case 4: { + data = (gpu->draw_y2 << 10) | gpu->draw_x2; + } break; + case 5: { + data = (gpu->off_y << 10) | gpu->off_x; + } break; + } + + gpu->gp1_10h_req = 0; + } + return data; } break; case 0x04: return gpu->gpustat | 0x1c000000; @@ -73,23 +92,15 @@ uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) { } uint16_t psx_gpu_read16(psx_gpu_t* gpu, uint32_t offset) { - switch (offset) { - case 0x00: return 0xaaaa; - case 0x04: return gpu->gpustat; - } + log_fatal("Unhandled 16-bit GPU read at offset %08x", offset); - log_warn("Unhandled 16-bit GPU read at offset %08x", offset); - - return 0x0; + exit(1); } uint8_t psx_gpu_read8(psx_gpu_t* gpu, uint32_t offset) { - switch (offset) { - case 0x00: return gpu->gpuread; - case 0x04: return gpu->gpustat; - } + log_fatal("Unhandled 8-bit GPU read at offset %08x", offset); - log_warn("Unhandled 8-bit GPU read at offset %08x", offset); + exit(1); return 0x0; } @@ -445,6 +456,21 @@ void gpu_cmd_a0(psx_gpu_t* gpu) { gpu->ysiz = ((gpu->ysiz - 1) & 0x1ff) + 1; gpu->tsiz = ((gpu->xsiz * gpu->ysiz) + 1) & 0xfffffffe; gpu->addr = gpu->xpos + (gpu->ypos * 1024); + + //log_set_quiet(0); + + log_fatal("pos=(%u, %u), siz=(%u, %u), tsiz=%08x, addr=%08x", + gpu->xpos, gpu->ypos, + gpu->xsiz, gpu->ysiz, + gpu->tsiz, gpu->addr + ); + + // system("pause > nul"); + + // if (gpu->event_cb_table[GPU_EVENT_VBLANK]) + // gpu->event_cb_table[GPU_EVENT_VBLANK](gpu); + + //log_set_quiet(1); } } break; @@ -815,6 +841,36 @@ void gpu_cmd_02(psx_gpu_t* gpu) { } } +void gpu_cmd_80(psx_gpu_t* gpu) { + switch (gpu->state) { + case GPU_STATE_RECV_CMD: { + gpu->state = GPU_STATE_RECV_ARGS; + gpu->cmd_args_remaining = 3; + } break; + + case GPU_STATE_RECV_ARGS: { + if (!gpu->cmd_args_remaining) { + gpu->state = GPU_STATE_RECV_DATA; + + uint32_t srcx = gpu->buf[1] & 0xffff; + uint32_t srcy = gpu->buf[1] >> 16; + uint32_t dstx = gpu->buf[2] & 0xffff; + uint32_t dsty = gpu->buf[2] >> 16; + uint32_t xsiz = gpu->buf[3] & 0xffff; + uint32_t ysiz = gpu->buf[3] >> 16; + + for (int y = 0; y < ysiz; y++) { + for (int x = 0; x < xsiz; x++) { + gpu->vram[(dstx + x) + (dsty + y) * 1024] = gpu->vram[(srcx + x) + (srcy + y) * 1024]; + } + } + + gpu->state = GPU_STATE_RECV_CMD; + } + } break; + } +} + void psx_gpu_update_cmd(psx_gpu_t* gpu) { switch (gpu->buf[0] >> 24) { case 0x00: /* nop */ break; @@ -833,6 +889,7 @@ void psx_gpu_update_cmd(psx_gpu_t* gpu) { case 0x65: gpu_cmd_64(gpu); break; case 0x66: gpu_cmd_64(gpu); break; case 0x68: gpu_cmd_68(gpu); break; + case 0x80: gpu_cmd_80(gpu); break; case 0xa0: gpu_cmd_a0(gpu); break; case 0xc0: gpu_cmd_c0(gpu); break; case 0xe1: { @@ -901,6 +958,11 @@ void psx_gpu_write32(psx_gpu_t* gpu, uint32_t offset, uint32_t value) { uint8_t cmd = value >> 24; switch (cmd) { + case 0x04: { + // log_set_quiet(0); + // log_fatal("GP1(04h) !!!!!!!!!!!!!!!!!"); + // log_set_quiet(1); + } break; case 0x08: gpu->display_mode = value & 0xffffff; @@ -908,23 +970,13 @@ void psx_gpu_write32(psx_gpu_t* gpu, uint32_t offset, uint32_t value) { gpu->event_cb_table[GPU_EVENT_DMODE](gpu); break; - case 0x10: - switch (value & 7) { - case 2: - gpu->gpuread = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8); - break; - case 3: - gpu->gpuread = (gpu->draw_y1 << 10) | gpu->draw_x1; - break; - case 4: - gpu->gpuread = (gpu->draw_y2 << 10) | gpu->draw_x2; - break; - case 5: // Drawing Offset - gpu->gpuread = (gpu->off_y << 10) | gpu->off_x; - break; - default: - break; - } + case 0x10: { + gpu->gp1_10h_req = value & 7; + + // log_set_quiet(0); + // log_fatal("GP1(10h) %u !!!!!!!!!!!!!!!!!", value & 7); + // log_set_quiet(1); + } break; } log_error("GP1(%02Xh) args=%06x", value >> 24, value & 0xffffff); diff --git a/psx/dev/gpu.h b/psx/dev/gpu.h index 47fa856..e14ec4a 100644 --- a/psx/dev/gpu.h +++ b/psx/dev/gpu.h @@ -78,6 +78,7 @@ struct psx_gpu_t { uint32_t c0_addr; int c0_xsiz, c0_ysiz; int c0_tsiz; + int gp1_10h_req; // GPU state uint32_t state; diff --git a/psx/input/sda.c b/psx/input/sda.c index 804f3b6..6b60229 100644 --- a/psx/input/sda.c +++ b/psx/input/sda.c @@ -39,12 +39,22 @@ void psxi_sda_write(void* udata, uint16_t data) { sda->tx_data = 0xff; sda->state = SDA_STATE_WFR; } + + // Memory card access + if (data == 0x81) { + sda->tx_data_ready = 1; + sda->tx_data = 0xff; + sda->state = SDA_STATE_WFR; + } } break; case SDA_STATE_WFR: { if (data == 'B') { sda->tx_data = sda->model; sda->state = SDA_STATE_TX_IDH; + } else if (data == 'R') { + sda->tx_data = 0xff; + sda->state = SDA_STATE_WFR; } } break;