set error code when GDC_CHECK_COMMAND is called for something other

than the most recent command

clear result after GDC_CHECK_COMMAND is called for a valid command

ignore invalid GDC_GETTOC2 commands
This commit is contained in:
Anthony Pesch 2017-12-04 19:04:30 -05:00
parent ba71415a3f
commit e032445a08
2 changed files with 94 additions and 77 deletions

View File

@ -93,18 +93,19 @@ enum {
};
enum {
GDC_STATUS_NONE = 0x0,
GDC_STATUS_ERROR = -1,
GDC_STATUS_INACTIVE = 0x0,
GDC_STATUS_ACTIVE = 0x1,
GDC_STATUS_DONE = 0x2,
GDC_STATUS_COMPLETE = 0x2,
GDC_STATUS_ABORT = 0x3,
GDC_STATUS_ERROR = 0x4,
};
enum {
GDC_ERROR_OK = 0x0,
GDC_ERROR_NO_DISC = 0x2,
GDC_ERROR_DISC_CHANGE = 0x6,
GDC_ERROR_SYSTEM = 0x1,
GDC_ERROR_NO_DISC = 0x2,
GDC_ERROR_INVALID_CMD = 0x5,
GDC_ERROR_DISC_CHANGE = 0x6,
};
static int bios_gdrom_override_format(struct bios *bios, int format) {
@ -140,7 +141,7 @@ static uint32_t bios_gdrom_send_cmd(struct bios *bios, uint32_t cmd_code,
uint32_t params) {
struct dreamcast *dc = bios->dc;
if (bios->status != GDC_STATUS_NONE) {
if (bios->status != GDC_STATUS_INACTIVE) {
return 0;
}
@ -173,6 +174,9 @@ static void bios_gdrom_mainloop(struct bios *bios) {
return;
}
/* by default, all commands report that they've completed successfully */
bios->status = GDC_STATUS_COMPLETE;
switch (bios->cmd_code) {
case GDC_PIOREAD:
case GDC_DMAREAD: {
@ -213,69 +217,78 @@ static void bios_gdrom_mainloop(struct bios *bios) {
uint32_t area = bios->params[0];
uint32_t dst = bios->params[1];
LOG_SYSCALL("GDC_GETTOC2 0=0x%x 1=0x%x", area, dst);
LOG_SYSCALL("GDC_GETTOC2 area=0x%x dst=0x%x", area, dst);
struct gd_toc_info toc;
gdrom_get_toc(gd, area, &toc);
struct gd_status_info stat;
gdrom_get_status(gd, &stat);
/* bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
byte | | | | | | | |
------------------------------------------------------
n*4+0 | track n fad (lsb)
------------------------------------------------------
n*4+1 | track n fad
------------------------------------------------------
n*4*2 | track n fad (msb)
------------------------------------------------------
n*4+3 | track n control | track n adr
------------------------------------------------------
396 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
397 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
398 | start track number
------------------------------------------------------
399 | start track control | start track adr
------------------------------------------------------
400 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
401 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
402 | end track number
------------------------------------------------------
403 | end track control | end track adr
------------------------------------------------------
404 | lead-out track fad (lsb)
------------------------------------------------------
405 | lead-out track fad
------------------------------------------------------
406 | lead-out track fad (msb)
------------------------------------------------------
407 | lead-out track ctrl | lead-out track adr */
uint8_t out[408];
for (int i = 0; i < ARRAY_SIZE(toc.entries); i++) {
struct gd_toc_entry *entry = &toc.entries[i];
out[i * 4 + 0] = (entry->fad & 0x000000ff);
out[i * 4 + 1] = (entry->fad & 0x0000ff00) >> 8;
out[i * 4 + 2] = (entry->fad & 0x00ff0000) >> 16;
out[i * 4 + 3] = ((entry->ctrl & 0xf) << 4) | (entry->adr & 0xf);
if (area == GD_AREA_HIGH && stat.format != GD_DISC_GDROM) {
/* only GD-ROMs have a high-density area. in this situation, the bios
doesn't set a result or error */
bios->status = GDC_STATUS_INACTIVE;
} else {
struct gd_toc_info toc;
gdrom_get_toc(gd, area, &toc);
/* bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
byte | | | | | | | |
------------------------------------------------------
n*4+0 | track n fad (lsb)
------------------------------------------------------
n*4+1 | track n fad
------------------------------------------------------
n*4*2 | track n fad (msb)
------------------------------------------------------
n*4+3 | track n control | track n adr
------------------------------------------------------
396 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
397 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
398 | start track number
------------------------------------------------------
399 | start track control | start track adr
------------------------------------------------------
400 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
401 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
------------------------------------------------------
402 | end track number
------------------------------------------------------
403 | end track control | end track adr
------------------------------------------------------
404 | lead-out track fad (lsb)
------------------------------------------------------
405 | lead-out track fad
------------------------------------------------------
406 | lead-out track fad (msb)
------------------------------------------------------
407 | lead-out track ctrl | lead-out track adr */
uint8_t out[408];
for (int i = 0; i < ARRAY_SIZE(toc.entries); i++) {
struct gd_toc_entry *entry = &toc.entries[i];
out[i * 4 + 0] = (entry->fad & 0x000000ff);
out[i * 4 + 1] = (entry->fad & 0x0000ff00) >> 8;
out[i * 4 + 2] = (entry->fad & 0x00ff0000) >> 16;
out[i * 4 + 3] = ((entry->ctrl & 0xf) << 4) | (entry->adr & 0xf);
}
out[396] = 0;
out[397] = 0;
out[398] = toc.first.fad & 0xff;
out[399] = ((toc.first.ctrl & 0xf) << 4) | (toc.first.adr & 0xf);
out[400] = 0;
out[401] = 0;
out[402] = toc.last.fad & 0xff;
out[403] = ((toc.last.ctrl & 0xf) << 4) | (toc.last.adr & 0xf);
out[404] = (toc.leadout.fad & 0x000000ff);
out[405] = (toc.leadout.fad & 0x0000ff00) >> 8;
out[406] = (toc.leadout.fad & 0x00ff0000) >> 16;
out[407] = ((toc.leadout.ctrl & 0xf) << 4) | (toc.leadout.adr & 0xf);
sh4_memcpy_to_guest(dc->mem, dst, &out, sizeof(out));
/* the bios doesn't perform a pio transfer to get the toc for this req,
it is cached, so there is no transfer size to record */
}
out[396] = 0;
out[397] = 0;
out[398] = toc.first.fad & 0xff;
out[399] = ((toc.first.ctrl & 0xf) << 4) | (toc.first.adr & 0xf);
out[400] = 0;
out[401] = 0;
out[402] = toc.last.fad & 0xff;
out[403] = ((toc.last.ctrl & 0xf) << 4) | (toc.last.adr & 0xf);
out[404] = (toc.leadout.fad & 0x000000ff);
out[405] = (toc.leadout.fad & 0x0000ff00) >> 8;
out[406] = (toc.leadout.fad & 0x00ff0000) >> 16;
out[407] = ((toc.leadout.ctrl & 0xf) << 4) | (toc.leadout.adr & 0xf);
sh4_memcpy_to_guest(dc->mem, dst, &out, sizeof(out));
/* the bios doesn't perform a pio transfer to get the toc for this req,
it is cached, so there is no transfer size to record */
} break;
case GDC_PLAY: {
@ -469,8 +482,6 @@ static void bios_gdrom_mainloop(struct bios *bios) {
LOG_FATAL("bios_gdrom_mainloop unexpected cmd=0x%x", bios->cmd_code);
} break;
}
bios->status = GDC_STATUS_DONE;
}
void bios_gdrom_vector(struct bios *bios) {
@ -558,14 +569,20 @@ void bios_gdrom_vector(struct bios *bios) {
LOG_SYSCALL("GDROM_CHECK_COMMAND 0x%x 0x%x", cmd_id, status);
ctx->r[0] = bios->status;
if (cmd_id == bios->cmd_id && bios->status != GDC_STATUS_NONE) {
sh4_memcpy_to_guest(dc->mem, status, &bios->result,
if (cmd_id != bios->cmd_id) {
/* error if something other than the most recent command is checked */
const uint32_t result[] = {GDC_ERROR_INVALID_CMD, 0, 0, 0};
sh4_memcpy_to_guest(dc->mem, status, result, sizeof(result));
ctx->r[0] = GDC_STATUS_ERROR;
} else {
sh4_memcpy_to_guest(dc->mem, status, bios->result,
sizeof(bios->result));
}
ctx->r[0] = bios->status;
bios->status = GDC_STATUS_NONE;
/* clear result so nothing is returned if queried a second time */
bios->status = GDC_STATUS_INACTIVE;
memset(bios->result, 0, sizeof(bios->result));
}
} break;
case GDROM_MAINLOOP: {
@ -591,7 +608,7 @@ void bios_gdrom_vector(struct bios *bios) {
*/
LOG_SYSCALL("GDROM_INIT");
bios->status = GDC_STATUS_NONE;
bios->status = GDC_STATUS_INACTIVE;
} break;
case GDROM_CHECK_DRIVE: {

View File

@ -50,8 +50,8 @@ static void cdi_get_toc(struct disc *disc, int area, struct track **first_track,
int *leadout_fad) {
struct cdi *cdi = (struct cdi *)disc;
/* cdi's have no high-density area */
CHECK_EQ(area, GD_AREA_SINGLE);
/* cdi's don't have a high-density area */
CHECK_NE(area, GD_AREA_HIGH);
/* the toc on cdi's represents all tracks / sessions */
struct session *first_session = &cdi->sessions[0];