cen64/si/pak.c
Simon Eriksson a54cbe042f si: Fix Memory Pak initialization
Thanks to bryc for researching this issue and reviewing this fix
2021-02-20 18:11:07 +01:00

142 lines
4.7 KiB
C

//
// si/pak.c: Controller pak routines
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2016, Mike Ryan.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifdef _WIN32
#include <wchar.h>
#endif
#include "pak.h"
#include "pak_transfer.h"
static uint8_t controller_pak_crc(uint8_t *data);
int controller_pak_read(struct controller *controller,
uint8_t *send_buf, uint8_t send_bytes,
uint8_t *recv_buf, uint8_t recv_bytes) {
uint16_t address = send_buf[1] << 8 | send_buf[2];
address &= ~0x1F; // lower 5 bits are address CRC
// printf("read from %04x\n", address);
if (controller->pak == PAK_MEM) {
if (address <= MEMPAK_SIZE - 0x20)
memcpy(recv_buf, (uint8_t *) (controller->mempak_save.ptr) + address, 0x20);
else
assert(0 && "invalid mempak address");
}
else if (controller->pak == PAK_TRANSFER)
transfer_pak_read(controller, send_buf, send_bytes, recv_buf, recv_bytes);
else {
uint8_t peripheral = 0x00;
if (controller->pak == PAK_RUMBLE)
peripheral = 0x80;
memset(recv_buf, peripheral, 0x20);
}
recv_buf[0x20] = controller_pak_crc(recv_buf);
return 0;
}
int controller_pak_write(struct controller *controller,
uint8_t *send_buf, uint8_t send_bytes,
uint8_t *recv_buf, uint8_t recv_bytes) {
uint16_t address = send_buf[1] << 8 | send_buf[2];
address &= ~0x1F; // lower 5 bits are a checksum
// printf("write to %04x\n", address);
if (address == 0x8000) {
// maybe only for transfer pak, unclear
if (send_buf[3] == 0xfe)
controller->pak_enabled = 0;
else if (send_buf[3] == 0x84)
controller->pak_enabled = 1;
}
else if (controller->pak == PAK_MEM) {
if (address <= MEMPAK_SIZE - 0x20)
memcpy((uint8_t *) (controller->mempak_save.ptr) + address, send_buf + 3, 0x20);
else
assert(0 && "Attempt to write past end of mempak");
}
else if (controller->pak == PAK_RUMBLE) {
if (address == 0xC000) {
if (send_buf[3] == 0x01) {
// printf("Enable rumble\n");
} else {
// printf("Disable rumble\n");
}
}
else {
// printf("Unknown rumble address\n");
}
}
else if (controller->pak == PAK_TRANSFER)
transfer_pak_write(controller, send_buf, send_bytes, recv_buf, recv_bytes);
recv_buf[0] = controller_pak_crc(send_buf+3);
return 0;
}
uint8_t controller_pak_crc(uint8_t *data) {
size_t i;
int mask;
uint8_t crc = 0;
for (i = 0; i <= 0x20; ++i) {
for (mask = 0x80; mask >= 1; mask >>= 1) {
uint8_t xor_tap = (crc & 0x80) ? 0x85 : 0x00;
crc <<= 1;
if (i < 0x20 && (data[i] & mask))
crc |= 1;
crc ^= xor_tap;
}
}
return crc;
}
void controller_pak_format(uint8_t *ptr) {
static uint8_t init_id_area[] = {
0x81, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x1A, 0x5F, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x66, 0x25, 0x99, 0xCD,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x1A, 0x5F, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x66, 0x25, 0x99, 0xCD,
0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x1A, 0x5F, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x66, 0x25, 0x99, 0xCD,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x1A, 0x5F, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x66, 0x25, 0x99, 0xCD,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
memset(ptr, 0, MEMPAK_SIZE);
memcpy(ptr, init_id_area, sizeof(init_id_area));
ptr[(MEMPAK_PAGE_SIZE * 1) + 1] = 0x71;
ptr[(MEMPAK_PAGE_SIZE * 2) + 1] = 0x71;
for (off_t i = 5; i < MEMPAK_NUM_PAGES; i++) {
ptr[(MEMPAK_PAGE_SIZE * 1) + (i * 2) + 1] = 0x03;
ptr[(MEMPAK_PAGE_SIZE * 2) + (i * 2) + 1] = 0x03;
}
}