Skip to content

Commit

Permalink
[DC] Add memory card support for Dreamcast
Browse files Browse the repository at this point in the history
Fixed maple_tx size wraparound bug
Implemented several commands for the maple memory card function
Saved about 1K of IRAM by decreasing the size of wait_100ns()
  • Loading branch information
breademan authored and darthcloud committed Aug 22, 2023
1 parent 729dc6b commit 74b98ba
Showing 1 changed file with 122 additions and 103 deletions.
225 changes: 122 additions & 103 deletions main/wired/maple.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "tools/util.h"
#include "adapter/adapter.h"
#include "adapter/config.h"
#include "adapter/memory_card.h"
#include "adapter/wired/dc.h"
#include "system/core0_stall.h"
#include "system/delay.h"
Expand All @@ -28,31 +29,34 @@
#define ID_RUMBLE 0x00000100
#define ID_MOUSE 0x00000200

#define CMD_INFO_REQ 0x01
#define CMD_EXT_INFO_REQ 0x02
#define CMD_RESET 0x03
#define CMD_SHUTDOWN 0x04
#define CMD_INFO_RSP 0x05
#define CMD_EXT_INFO_RSP 0x06
#define CMD_ACK 0x07
#define CMD_DATA_TX 0x08
#define CMD_GET_CONDITION 0x09
#define CMD_MEM_INFO_REQ 0x0A
#define CMD_BLOCK_READ 0x0B
#define CMD_BLOCK_WRITE 0x0C
#define CMD_SET_CONDITION 0x0E
#define CMD_INFO_REQ 0x01
#define CMD_EXT_INFO_REQ 0x02
#define CMD_RESET 0x03
#define CMD_SHUTDOWN 0x04
#define CMD_INFO_RSP 0x05
#define CMD_EXT_INFO_RSP 0x06
#define CMD_ACK 0x07
#define CMD_DATA_TX 0x08
#define CMD_GET_CONDITION 0x09
#define CMD_MEM_INFO_REQ 0x0A
#define CMD_BLOCK_READ 0x0B
#define CMD_BLOCK_WRITE 0x0C
#define CMD_WRITE_COMPLETE 0x0D
#define CMD_SET_CONDITION 0x0E

#define ADDR_MASK 0x3F
#define ADDR_MAIN 0x20
#define ADDR_MEM 0x01
#define ADDR_RUMBLE 0x02

#define DESC_CTRL 0x000F06FE
#define DESC_CTRL_ALT 0x003FFFFF
#define DESC_VMU 0x7E7E3F40
#define DESC_RUMBLE 0x01010000
#define DESC_MOUSE 0x000E0700
#define DESC_KB 0x01020080
#define DESC_CTRL 0x000F06FE
#define DESC_CTRL_ALT 0x003FFFFF
#define DESC_VMU_TIMER 0x7E7E3F40
#define DESC_VMU_SCREEN 0x00051000
#define DESC_VMU_MEMORY 0x000F4100
#define DESC_RUMBLE 0x01010000
#define DESC_MOUSE 0x000E0700
#define DESC_KB 0x01020080

#define PWR_CTRL 0xAE01F401
#define PWR_VMU 0x7C008200
Expand All @@ -63,7 +67,13 @@
#define TIMEOUT 8
#define TIMEOUT_ABORT 100

#define wait_100ns() asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
#define VMU_BLOCK_SIZE 512
#define VMU_WRITE_ACCESSES 4
#define VMU_READ_ACCESSES 1

#define wait_100ns() asm("movi a8, 5\n\tloop a8, waitend%=\n\tnop\n\twaitend%=:\n":::"a8");
#define wait_500ns() asm("movi a8, 49\n\tloop a8, waitend%=\n\tnop\n\twaitend%=:\n":::"a8");
#define wait_200ns() asm("movi a8, 16\n\tloop a8, waitend%=\n\tnop\n\twaitend%=:\n":::"a8");
#define maple_fix_byte(s, a, b) (s ? ((a << s) | (b >> (8 - s))) : b)

struct maple_pkt {
Expand Down Expand Up @@ -108,12 +118,10 @@ static const uint8_t ctrl_area_dir_name[] = {
0x6C, 0x6C, 0x6F, 0x72, 0x20, 0x20, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
};

#if 0
static const uint8_t vmu_area_dir_name[] = {
0x69, 0x56, 0x00, 0xFF, 0x6C, 0x61, 0x75, 0x73, 0x6D, 0x65, 0x4D, 0x20, 0x20, 0x79, 0x72, 0x6F,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
};
#endif

static const uint8_t rumble_area_dir_name[] = {
0x75, 0x50, 0x00, 0xFF, 0x50, 0x20, 0x75, 0x72, 0x20, 0x75, 0x72, 0x75, 0x6B, 0x63, 0x61, 0x50,
Expand Down Expand Up @@ -143,6 +151,11 @@ static const uint8_t dc_mouse_axes_idx[ADAPTER_MAX_AXES] =
2, 3, 1, 0, 5, 4
};

static const uint8_t vmu_media_info[] = {
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFE, 0x00, 0xFF, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D,
0x00, 0x1F, 0x00, 0xC8, 0x00, 0x80, 0x00, 0x00,
};

#else
static uint32_t cur_us = 0, pre_us = 0;
#endif
Expand Down Expand Up @@ -177,7 +190,7 @@ static inline void load_mouse_axes(uint8_t port, uint16_t *axes) {
}
}

static void maple_tx(uint32_t port, uint32_t maple0, uint32_t maple1, uint8_t *data, uint8_t len) {
static void maple_tx(uint32_t port, uint32_t maple0, uint32_t maple1, uint8_t *data, uint32_t len) {
uint8_t *crc = data + (len - 1);
*crc = 0x00;

Expand All @@ -188,62 +201,28 @@ static void maple_tx(uint32_t port, uint32_t maple0, uint32_t maple1, uint8_t *d
gpio_set_direction_iram(gpio_pin[port][1], GPIO_MODE_OUTPUT);
core0_stall_start();
GPIO.out_w1tc = maple0;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple1;
wait_100ns();
wait_100ns();
wait_200ns();

for (uint32_t bit = 0; bit < len*8; ++data) {
for (uint32_t mask = 0x80; mask; mask >>= 1, ++bit) {
GPIO.out_w1ts = maple0;
wait_100ns();
wait_100ns();
wait_200ns();
if (*data & mask) {
GPIO.out_w1ts = maple1;
}
Expand All @@ -252,13 +231,11 @@ static void maple_tx(uint32_t port, uint32_t maple0, uint32_t maple1, uint8_t *d
}
wait_100ns();
GPIO.out_w1tc = maple0;
wait_100ns();
wait_100ns();
wait_200ns();
mask >>= 1;
++bit;
GPIO.out_w1ts = maple1;
wait_100ns();
wait_100ns();
wait_200ns();
if (*data & mask) {
GPIO.out_w1ts = maple0;
}
Expand All @@ -267,49 +244,24 @@ static void maple_tx(uint32_t port, uint32_t maple0, uint32_t maple1, uint8_t *d
}
wait_100ns();
GPIO.out_w1tc = maple1;
wait_100ns();
wait_100ns();
wait_200ns();
}
*crc ^= *data;
}
GPIO.out_w1ts = maple0;
wait_100ns();
GPIO.out_w1ts = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple1;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple0;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple0;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1tc = maple0;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple0;
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_100ns();
wait_500ns();
GPIO.out_w1ts = maple1;

core0_stall_end();
Expand All @@ -330,6 +282,8 @@ static unsigned maple_rx(unsigned cause) {
uint32_t bad_frame;
uint8_t len, cmd, src, dst, crc = 0;
uint32_t maple1;
uint8_t phase;
uint8_t block_no;

if (maple0) {
core0_stall_start();
Expand Down Expand Up @@ -495,6 +449,9 @@ static unsigned maple_rx(unsigned cause) {
if (config.out_cfg[port].acc_mode & ACC_RUMBLE) {
pkt.src |= ADDR_RUMBLE;
}
if (config.out_cfg[port].acc_mode & ACC_MEM) {
pkt.src |= ADDR_MEM;
}
pkt.dst = dst;
switch (cmd) {
case CMD_INFO_REQ:
Expand Down Expand Up @@ -596,6 +553,68 @@ static unsigned maple_rx(unsigned cause) {
break;
}
break;
case ADDR_MEM:
pkt.src = src;
pkt.dst = dst;
switch(cmd) {
case CMD_INFO_REQ:
pkt.len = 28;
pkt.cmd = CMD_INFO_RSP;
pkt.data32[0] = ID_VMU_MEM;
pkt.data32[1] = DESC_VMU_MEMORY;
pkt.data32[2] = 0;
pkt.data32[3] = 0;
memcpy((void *)&pkt.data32[4], vmu_area_dir_name, sizeof(vmu_area_dir_name));
memcpy((void *)&pkt.data32[12], brand, sizeof(brand));
pkt.data32[27] = PWR_VMU;
maple_tx(port, maple0, maple1, pkt.data, pkt.len * 4 + 5);
break;
case CMD_EXT_INFO_REQ: /* unimplemented */
case CMD_GET_CONDITION:
case CMD_MEM_INFO_REQ:
pkt.len = 0x07;
pkt.cmd = CMD_DATA_TX;
pkt.data32[0] = ID_VMU_MEM;
memcpy((void *)&pkt.data32[1], vmu_media_info, sizeof(vmu_media_info));
maple_tx(port, maple0, maple1, pkt.data, pkt.len * 4 + 5);
break;
case CMD_BLOCK_READ:
pkt.len = 0x82;
pkt.cmd = CMD_DATA_TX;
pkt.data32[0] = ID_VMU_MEM;
phase = (uint8_t)((pkt.data32[1] >> 16) & 0x00FF);
if (phase) {
ets_printf("Block Read with unexpected phase: 0x%02X, expected 0\n", phase);
}
block_no = (uint8_t)((pkt.data32[1]) & 0x00FF);
mc_read(block_no * VMU_BLOCK_SIZE, (void *)&pkt.data32[2], VMU_BLOCK_SIZE);
maple_tx(port, maple0, maple1, pkt.data, pkt.len * 4 + 5);
break;
case CMD_BLOCK_WRITE:
if (pkt.len != (32 + 2)) {
ets_printf("Unexpected Block Write packet length: 0x%02X, expected 0x22\n", pkt.len);
}
pkt.len = 0x00;
pkt.cmd = CMD_ACK;
if ((!bad_frame) && pkt.data32[0] == ID_VMU_MEM) {
phase = (uint8_t)((pkt.data32[1] >> 16) & 0x00FF);
block_no = (uint8_t)((pkt.data32[1]) & 0x00FF);
/* Data is written to the MC module in wire byte order. */
/* If creating a read/write function, this must be accounted for. */
mc_write((block_no * VMU_BLOCK_SIZE) + (128 * phase), (void *)&pkt.data32[2], 128);
}
maple_tx(port, maple0, maple1, pkt.data, pkt.len * 4 + 5);
break;
case CMD_WRITE_COMPLETE:
pkt.len = 0x00;
pkt.cmd = CMD_ACK;
maple_tx(port, maple0, maple1, pkt.data, pkt.len * 4 + 5);
break;
default:
ets_printf("%02X: Unk cmd: 0x%02X\n", dst, cmd);
break;
}
break;
}
break;
}
Expand Down

0 comments on commit 74b98ba

Please sign in to comment.