From a8501a2f6245efa375dbdffcdd812981546b5a32 Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Sat, 25 Nov 2017 10:39:37 -0500 Subject: [PATCH] make vmu respond to device info request with LCD / Clock support added stubs for LCD / Clock commands --- src/guest/holly/holly.c | 6 -- src/guest/maple/controller.c | 43 ++++---- src/guest/maple/maple.c | 35 +++++-- src/guest/maple/maple_types.h | 26 ++--- src/guest/maple/vmu.c | 186 +++++++++++++++++++++------------- 5 files changed, 171 insertions(+), 125 deletions(-) diff --git a/src/guest/holly/holly.c b/src/guest/holly/holly.c index e5bc69c1..2de7251d 100644 --- a/src/guest/holly/holly.c +++ b/src/guest/holly/holly.c @@ -18,10 +18,6 @@ struct reg_cb holly_cb[NUM_HOLLY_REGS]; /* * ch2 dma */ -static void holly_ch2_dma_stop(struct holly *hl) { - /* nop as DMA is always performed synchronously */ -} - static void holly_ch2_dma(struct holly *hl) { struct sh4 *sh4 = hl->dc->sh4; @@ -517,8 +513,6 @@ REG_W32(holly_cb, SB_C2DST) { if (*hl->SB_C2DST) { holly_ch2_dma(hl); - } else { - holly_ch2_dma_stop(hl); } } diff --git a/src/guest/maple/controller.c b/src/guest/maple/controller.c index 306dfdab..4387345a 100644 --- a/src/guest/maple/controller.c +++ b/src/guest/maple/controller.c @@ -44,50 +44,45 @@ static int controller_frame(struct maple_device *dev, maple_decode_addr(req->dst_addr, &port, &unit); struct maple_device *sub = maple_get_device(dev->mp, port, unit); - if (sub != dev) { - return sub && sub->frame(sub, req, res); + if (!sub) { + return 0; } - switch (req->command) { + if (sub != dev) { + return sub->frame(sub, req, res); + } + + switch (req->cmd) { case MAPLE_REQ_DEVINFO: { - /* based on captured result of real Dreamcast controller */ + char *name = "Dreamcast Controller"; + char *license = "Produced By or Under License From SEGA ENTERPRISES,LTD."; struct maple_device_info info = {0}; info.func = MAPLE_FUNC_CONTROLLER; info.data[0] = 0xfe060f00; info.region = 0xff; - strncpy_pad_spaces(info.name, "Dreamcast Controller", sizeof(info.name)); - strncpy_pad_spaces( - info.license, - "Produced By or Under License From SEGA ENTERPRISES,LTD.", - sizeof(info.license)); + strncpy_pad_spaces(info.name, name, sizeof(info.name)); + strncpy_pad_spaces(info.license, license, sizeof(info.license)); info.standby_power = 0x01ae; info.max_power = 0x01f4; - res->command = MAPLE_RES_DEVINFO; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; + res->cmd = MAPLE_RES_DEVINFO; res->num_words = sizeof(info) >> 2; memcpy(res->params, &info, sizeof(info)); } break; case MAPLE_REQ_GETCOND: { - res->command = MAPLE_RES_TRANSFER; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; + res->cmd = MAPLE_RES_TRANSFER; res->num_words = sizeof(ctrl->cnd) >> 2; memcpy(res->params, &ctrl->cnd, sizeof(ctrl->cnd)); } break; - default: { - res->command = MAPLE_RES_BADCMD; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; - res->num_words = 0; - } break; + default: + res->cmd = MAPLE_RES_BADCMD; + break; } - /* when a primary device identifies itself in the response to a command, it - sets the bit for each connected sub-device in addition to bit 5 */ + /* when a primary device identifies itself in the response to a cmd, it sets + the bit for each connected sub-device in addition to bit 5 */ for (int i = 0; i < MAPLE_MAX_UNITS - 1; i++) { struct maple_device *sub = maple_get_device(dev->mp, port, i); @@ -142,7 +137,7 @@ struct maple_device *controller_create(struct maple *mp, int port) { ctrl->frame = &controller_frame; /* default state */ - ctrl->cnd.function = MAPLE_FUNC_CONTROLLER; + ctrl->cnd.func = MAPLE_FUNC_CONTROLLER; ctrl->cnd.buttons = 0xffff; ctrl->cnd.rtrig = ctrl->cnd.ltrig = 0; ctrl->cnd.joyy = ctrl->cnd.joyx = ctrl->cnd.joyx2 = ctrl->cnd.joyy2 = 0x80; diff --git a/src/guest/maple/maple.c b/src/guest/maple/maple.c index 8d2109d6..5034a73d 100644 --- a/src/guest/maple/maple.c +++ b/src/guest/maple/maple.c @@ -24,30 +24,45 @@ static void maple_unregister_dev(struct maple *mp, int port, int unit) { static void maple_register_dev(struct maple *mp, const char *device_type, int port, int unit) { - CHECK(!mp->devs[port][unit], - "maple_register_dev already registered for port=%d unit=%d", port, - unit); struct maple_device **dev = &mp->devs[port][unit]; + CHECK(!*dev, "maple_register_dev already registered for port=%d unit=%d", + port, unit); if (!strcmp(device_type, "controller")) { *dev = controller_create(mp, port); } else if (!strcmp(device_type, "vmu")) { *dev = vmu_create(mp, port); } else { - LOG_WARNING("Unsupported device type: %s", device_type); + LOG_WARNING("maple_register_dev unsupported device_type=%s", device_type); } } -int maple_handle_frame(struct maple *mp, int port, union maple_frame *frame, +int maple_handle_frame(struct maple *mp, int port, union maple_frame *req, union maple_frame *res) { CHECK(port >= 0 && port < MAPLE_NUM_PORTS); - /* note, not all maple devices have the same frame format. for example, the - check-gd disc sends a command to some kind of debug device which has the - frame data bswap'd. for this reason, it's not valid to inspect the frame - data in order to send the frame directly to the correct sub-device */ struct maple_device *dev = mp->devs[port][MAPLE_MAX_UNITS - 1]; - return dev && dev->frame(dev, frame, res); + + if (!dev) { + return 0; + } + + /* initialize response */ + memset(res, 0, sizeof(*res)); + res->dst_addr = req->src_addr; + res->src_addr = req->dst_addr; + + /* send to primary device */ + if (!dev->frame(dev, req, res)) { + return 0; + } + + /* in general, these errors are rare and more often a bug in the emulator */ + if ((int8_t)res->cmd < 0) { + LOG_WARNING("maple_handle_frame port=%d error=0x%x", port, res->cmd); + } + + return 1; } void maple_handle_input(struct maple *mp, int port, int button, diff --git a/src/guest/maple/maple_types.h b/src/guest/maple/maple_types.h index d4dca7ce..47e64aac 100644 --- a/src/guest/maple/maple_types.h +++ b/src/guest/maple/maple_types.h @@ -24,14 +24,14 @@ enum maple_pattern { function code */ enum maple_fn { MAPLE_FUNC_CONTROLLER = 0x01000000, - MAPLE_FUNC_MEMORYCARD = 0x02000000, - MAPLE_FUNC_LCDDISPLAY = 0x04000000, + MAPLE_FUNC_MEMCARD = 0x02000000, + MAPLE_FUNC_LCD = 0x04000000, MAPLE_FUNC_CLOCK = 0x08000000, MAPLE_FUNC_MICROPHONE = 0x10000000, MAPLE_FUNC_ARGUN = 0x20000000, MAPLE_FUNC_KEYBOARD = 0x40000000, MAPLE_FUNC_LIGHTGUN = 0x80000000, - MAPLE_FUNC_PURUPURUPACK = 0x00010000, + MAPLE_FUNC_PURUPURU = 0x00010000, MAPLE_FUNC_MOUSE = 0x00020000 }; @@ -48,9 +48,9 @@ enum maple_cmd { MAPLE_RES_TRANSFER = (uint8_t)8, MAPLE_REQ_GETCOND = (uint8_t)9, MAPLE_REQ_GETMEMINFO = (uint8_t)10, - MAPLE_REQ_BLOCKREAD = (uint8_t)11, - MAPLE_REQ_BLOCKWRITE = (uint8_t)12, - MAPLE_REQ_BLOCKSYNC = (uint8_t)13, + MAPLE_REQ_BLKREAD = (uint8_t)11, + MAPLE_REQ_BLKWRITE = (uint8_t)12, + MAPLE_REQ_BLKSYNC = (uint8_t)13, MAPLE_REQ_SETCOND = (uint8_t)14, MAPLE_RES_NONE = (uint8_t)-1, MAPLE_RES_BADFUNC = (uint8_t)-2, @@ -77,7 +77,7 @@ union maple_transfer { header */ union maple_frame { struct { - uint32_t command : 8; + uint32_t cmd : 8; uint32_t dst_addr : 8; uint32_t src_addr : 8; uint32_t num_words : 8; @@ -108,7 +108,7 @@ struct maple_device_info { /* response MAPLE_REQ_GETCOND */ struct maple_cond { - uint32_t function; + uint32_t func; /* buttons bitfield contains 0s for pressed buttons and 1s for unpressed */ uint16_t buttons; /* opposite of the buttons, 0 is unpressed for the triggers */ @@ -123,9 +123,9 @@ struct maple_cond { /* response to MAPLE_REQ_GETMEMINFO */ struct maple_meminfo { - uint32_t function; + uint32_t func; uint16_t num_blocks; - uint16_t partiion; + uint16_t partition; uint16_t root_block; uint16_t fat_block; uint16_t fat_num_blocks; @@ -137,9 +137,9 @@ struct maple_meminfo { uint16_t reserved[2]; }; -/* response to MAPLE_REQ_BLOCKREAD */ -struct maple_blockread { - uint32_t function; +/* response to MAPLE_REQ_BLKREAD */ +struct maple_blkread { + uint32_t func; uint32_t block; uint32_t data[]; }; diff --git a/src/guest/maple/vmu.c b/src/guest/maple/vmu.c index 87714a81..cb9cb266 100644 --- a/src/guest/maple/vmu.c +++ b/src/guest/maple/vmu.c @@ -3,10 +3,12 @@ #include "guest/maple/maple.h" #include "guest/maple/vmu_default.inc" -#define VMU_BLOCK_SIZE 512 -#define VMU_BLOCK_WORDS (512 >> 2) -#define VMU_BLOCK_OFFSET(blk, phase) \ - ((blk)*VMU_BLOCK_SIZE + (phase) * (VMU_BLOCK_SIZE >> 2)) +#define BLK_SIZE 512 +#define BLK_WORDS (512 >> 2) +#define BLK_OFFSET(blk, phase) ((blk)*BLK_SIZE + (phase) * (BLK_SIZE >> 2)) + +#define LCD_WIDTH 48 +#define LCD_HEIGHT 32 struct vmu { struct maple_device; @@ -18,7 +20,7 @@ struct vmu { static void vmu_write_bin(struct vmu *vmu, int block, int phase, const void *buffer, int num_words) { - int offset = VMU_BLOCK_OFFSET(block, phase); + int offset = BLK_OFFSET(block, phase); int size = num_words << 2; FILE *file = fopen(vmu->filename, "r+b"); @@ -32,7 +34,7 @@ static void vmu_write_bin(struct vmu *vmu, int block, int phase, static void vmu_read_bin(struct vmu *vmu, int block, int phase, void *buffer, int num_words) { - int offset = VMU_BLOCK_OFFSET(block, phase); + int offset = BLK_OFFSET(block, phase); int size = num_words << 2; FILE *file = fopen(vmu->filename, "rb"); @@ -57,103 +59,143 @@ static int vmu_frame(struct maple_device *dev, const union maple_frame *req, union maple_frame *res) { struct vmu *vmu = (struct vmu *)dev; - switch (req->command) { + switch (req->cmd) { case MAPLE_REQ_DEVINFO: { - /* based on captured result of real Dreamcast VMU */ + char *name = "Visual Memory"; + char *license = "Produced By or Under License From SEGA ENTERPRISES,LTD."; struct maple_device_info info; - info.func = MAPLE_FUNC_MEMORYCARD; - info.data[0] = 0x00410f00; + info.func = MAPLE_FUNC_CLOCK | MAPLE_FUNC_LCD | MAPLE_FUNC_MEMCARD; + info.data[0] = 0x403f7e7e; /* clock */ + info.data[1] = 0x00100500; /* lcd */ + info.data[2] = 0x00410f00; /* memcard */ info.region = 0xff; - strncpy_pad_spaces(info.name, "Visual Memory", sizeof(info.name)); - strncpy_pad_spaces( - info.license, - "Produced By or Under License From SEGA ENTERPRISES,LTD.", - sizeof(info.license)); + strncpy_pad_spaces(info.name, name, sizeof(info.name)); + strncpy_pad_spaces(info.license, license, sizeof(info.license)); info.standby_power = 0x007c; info.max_power = 0x0082; - res->command = MAPLE_RES_DEVINFO; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; + res->cmd = MAPLE_RES_DEVINFO; res->num_words = sizeof(info) >> 2; memcpy(res->params, &info, sizeof(info)); } break; case MAPLE_REQ_GETMEMINFO: { - static struct maple_meminfo vmu_meminfo = {MAPLE_FUNC_MEMORYCARD, - 0xff, - 0x0, - 0xff, - 0xfe, - 0x1, - 0xfd, - 0xd, - 0x0, - 0xc8, - 0x1f, - {0x0, 0x0}}; - uint32_t func = req->params[0]; - CHECK_EQ(func, MAPLE_FUNC_MEMORYCARD); + CHECK_EQ(func, MAPLE_FUNC_MEMCARD); uint32_t partition = req->params[1] & 0xff; CHECK_EQ(partition, 0); - res->command = MAPLE_RES_TRANSFER; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; - res->num_words = sizeof(vmu_meminfo) >> 2; - memcpy(res->params, &vmu_meminfo, sizeof(vmu_meminfo)); + struct maple_meminfo meminfo = {0}; + meminfo.func = MAPLE_FUNC_MEMCARD; + meminfo.num_blocks = 0xff; + meminfo.partition = 0x0; + meminfo.root_block = 0xff; + meminfo.fat_block = 0xfe; + meminfo.fat_num_blocks = 0x1; + meminfo.dir_block = 0xfd; + meminfo.dir_num_blocks = 0xd; + meminfo.icon = 0x0; + meminfo.data_block = 0xc8; + meminfo.data_num_blocks = 0x1f; + + res->cmd = MAPLE_RES_TRANSFER; + res->num_words = sizeof(meminfo) >> 2; + memcpy(res->params, &meminfo, sizeof(meminfo)); } break; - case MAPLE_REQ_BLOCKREAD: { + case MAPLE_REQ_BLKREAD: { uint32_t func = req->params[0]; - CHECK_EQ(func, MAPLE_FUNC_MEMORYCARD); + CHECK_EQ(func, MAPLE_FUNC_MEMCARD); - int partition, block, phase; - vmu_parse_block_param(req->params[1], &partition, &block, &phase); - CHECK_EQ(partition, 0); - CHECK_EQ(phase, 0); + switch (func) { + case MAPLE_FUNC_MEMCARD: { + int partition, block, phase; + vmu_parse_block_param(req->params[1], &partition, &block, &phase); + CHECK_EQ(partition, 0); + CHECK_EQ(phase, 0); - struct maple_blockread vmu_read = {MAPLE_FUNC_MEMORYCARD, req->params[1]}; + struct maple_blkread blkread = {0}; + blkread.func = MAPLE_FUNC_MEMCARD; + blkread.block = req->params[1]; - res->command = MAPLE_RES_TRANSFER; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; - res->num_words = (sizeof(vmu_read) >> 2) + VMU_BLOCK_WORDS; - memcpy(res->params, &vmu_read, sizeof(vmu_read)); - vmu_read_bin(vmu, block, phase, &res->params[sizeof(vmu_read) >> 2], - VMU_BLOCK_WORDS); + res->cmd = MAPLE_RES_TRANSFER; + res->num_words = (sizeof(blkread) >> 2) + BLK_WORDS; + memcpy(res->params, &blkread, sizeof(blkread)); + vmu_read_bin(vmu, block, phase, &res->params[sizeof(blkread) >> 2], + BLK_WORDS); + } break; + + default: + res->cmd = MAPLE_RES_BADFUNC; + break; + } } break; - case MAPLE_REQ_BLOCKWRITE: { + case MAPLE_REQ_BLKWRITE: { uint32_t func = req->params[0]; - CHECK_EQ(func, MAPLE_FUNC_MEMORYCARD); - int partition, block, phase; - vmu_parse_block_param(req->params[1], &partition, &block, &phase); - CHECK_EQ(partition, 0); + switch (func) { + case MAPLE_FUNC_MEMCARD: { + int partition, block, phase; + vmu_parse_block_param(req->params[1], &partition, &block, &phase); + CHECK_EQ(partition, 0); - vmu_write_bin(vmu, block, phase, &req->params[2], req->num_words - 2); + vmu_write_bin(vmu, block, phase, &req->params[2], req->num_words - 2); - res->command = MAPLE_RES_ACK; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; - res->num_words = 0; + res->cmd = MAPLE_RES_ACK; + } break; + + case MAPLE_FUNC_LCD: { +#if 0 + /* TODO print this somewhere */ + const uint8_t *data = (const uint8_t *)&req->params[2]; + for (int y = LCD_HEIGHT-1; y >= 0; y--) { + for (int x = LCD_WIDTH-1; x >= 0; x--) { + int byte = x / 8; + int mask = 0x80 >> (x % 8); + if (data[y * (LCD_WIDTH / 8) + byte] & mask) { + printf("*"); + } else { + printf(" "); + } + } + printf("\n"); + } +#endif + res->cmd = MAPLE_RES_ACK; + } break; + + default: + res->cmd = MAPLE_RES_BADFUNC; + break; + } } break; - case MAPLE_REQ_BLOCKSYNC: { - res->command = MAPLE_RES_ACK; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; - res->num_words = 0; + case MAPLE_REQ_BLKSYNC: + res->cmd = MAPLE_RES_ACK; + break; + + case MAPLE_REQ_SETCOND: { + uint32_t func = req->params[0]; + + switch (func) { + case MAPLE_FUNC_CLOCK: { +#if 0 + /* TODO emit a a beep sound */ + uint32_t beep = req->params[1]; +#endif + res->cmd = MAPLE_RES_ACK; + } break; + + default: + res->cmd = MAPLE_RES_BADFUNC; + break; + } } break; - default: { - res->command = MAPLE_RES_BADCMD; - res->dst_addr = req->src_addr; - res->src_addr = req->dst_addr; - res->num_words = 0; - } break; + default: + res->cmd = MAPLE_RES_BADCMD; + break; } return 1;