mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-05 06:19:27 -04:00
a54cbe042f
Thanks to bryc for researching this issue and reviewing this fix
142 lines
4.7 KiB
C
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;
|
|
}
|
|
}
|