snes: MSU1 audio support by dent^nz and ElectronAsh (#602)
Co-authored-by: Karl Lurman <karl.lurman@wilsongroupau.com>
This commit is contained in:
@@ -3,10 +3,22 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../../file_io.h"
|
||||
#include "../../user_io.h"
|
||||
#include "../../spi.h"
|
||||
|
||||
static uint8_t hdr[512];
|
||||
static uint16_t msu_currenttrack = 0x0000;
|
||||
const uint64_t MSU_AUDIO_SECTOR_SENT = 0x00000000101;
|
||||
const uint64_t MSU_AUDIO_TRACKMOUNTED = 0x00000000201;
|
||||
const uint64_t MSU_AUDIO_SENDING_SECTOR = 0x00000000301;
|
||||
const uint64_t MSU_AUDIO_TRACKMISSING = 0x00000000401;
|
||||
|
||||
const uint64_t MSU_DATA_SECTOR_SENT = 0x00000000102;
|
||||
const uint64_t MSU_DATA_FILEMOUNTED = 0x00000000202;
|
||||
const uint64_t MSU_DATA_SENDING_SECTOR = 0x00000000302;
|
||||
|
||||
enum HeaderField {
|
||||
CartName = 0x00,
|
||||
@@ -309,4 +321,221 @@ void snes_patch_bs_header(fileTYPE *f, uint8_t *buf)
|
||||
buf[0xFDA] = 0x33;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This gets set by snes_msu_init for use by MSU-1 support later
|
||||
char snes_romFileName[1024] = { 0 };
|
||||
uint8_t topup_buffer = 0;
|
||||
|
||||
//uint8_t msu_data_array[0x2000000];
|
||||
uint8_t msu_data_loaded = 0x00;
|
||||
|
||||
void snes_msu_send_command(uint64_t cmd)
|
||||
{
|
||||
spi_uio_cmd_cont(UIO_CD_SET);
|
||||
spi_w((cmd >> 0) & 0xFFFF);
|
||||
spi_w((cmd >> 16) & 0xFFFF);
|
||||
spi_w(((cmd >> 32) & 0x00FF) | 0x00 << 8);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
void snes_msu_init(const char* name)
|
||||
{
|
||||
fileTYPE f = {};
|
||||
// static char msuDataFileName[1024] = { 0 };
|
||||
// Clear our our rom file name
|
||||
memset(snes_romFileName, 0, 1024);
|
||||
strncpy(snes_romFileName, name, strlen(name) - 4);
|
||||
|
||||
printf("SNES MSU - Rom named '%s' initialised\n", name);
|
||||
msu_currenttrack = 0x0000;
|
||||
|
||||
// TODO msu1 data file
|
||||
// sprintf(msuDataFileName, "%s.msu", snes_romFileName);
|
||||
// printf("SNES MSU - Checking for MSU datafile: %s\n", msuDataFileName);
|
||||
// if (!FileOpen(&f, msuDataFileName)) {
|
||||
// printf("SNES MSU - MSU datafile not found");
|
||||
// return;
|
||||
// }
|
||||
//else user_io_file_mount(msuDataFileName, 2);
|
||||
msu_data_loaded = 0x01;
|
||||
topup_buffer = 0;
|
||||
}
|
||||
|
||||
static int need_reset=0;
|
||||
static uint8_t has_command = 0;
|
||||
|
||||
int snes_msu_send_data(fileTYPE *f, uint8_t *buf)
|
||||
{
|
||||
int chunk = 1024;
|
||||
FileReadAdv(f, buf, chunk);
|
||||
// set index byte
|
||||
user_io_set_index(2);
|
||||
user_io_set_download(1);
|
||||
user_io_file_tx_data(buf, chunk);
|
||||
user_io_set_download(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int snes_msu_jump_sector(fileTYPE *f, uint32_t sector)
|
||||
{
|
||||
__off64_t off64 = sector;
|
||||
off64 = off64 * 1024;
|
||||
printf("SNES MSU - jumping to sector: 0x%X\n", sector);
|
||||
|
||||
return FileSeek(f, off64, SEEK_SET);
|
||||
}
|
||||
|
||||
void snes_poll(void)
|
||||
{
|
||||
static fileTYPE f = {};
|
||||
static char SelectedPath[1024] = { 0 };
|
||||
static char msuErrorMessage[256] = { 0 };
|
||||
static uint8_t last_req = 255;
|
||||
static uint16_t command = 0X0000;
|
||||
static uint16_t command_payload_lower = 0X0000;
|
||||
static uint16_t command_payload_middle = 0X0000;
|
||||
static uint16_t command_payload_upper = 0X0000;
|
||||
static uint8_t buf[1024];
|
||||
|
||||
static uint16_t msu_trackout = 0;
|
||||
static uint8_t msu_trackrequest = 0;
|
||||
static uint8_t msu_trackmounted = 0;
|
||||
static uint8_t msu_trackmissing = 0;
|
||||
static uint8_t msu_sector_jumping = 0;
|
||||
static uint8_t msu_sector_requested = 0;
|
||||
static uint8_t send_sector = 0;
|
||||
static uint8_t data_req = 0;
|
||||
|
||||
if (has_command) {
|
||||
// What was the command?
|
||||
|
||||
if (command == 0x0034) {
|
||||
// Next sector requested
|
||||
send_sector = 1;
|
||||
msu_trackrequest = 0;
|
||||
}
|
||||
|
||||
if (command == 0x0035) {
|
||||
// Unmount any existing tracks
|
||||
msu_trackmounted = 0;
|
||||
// track requested is in next word
|
||||
msu_trackrequest = 1;
|
||||
send_sector = 0;
|
||||
printf("\x1b[32mSNES MSU: Track requested\n\x1b[0m");
|
||||
}
|
||||
|
||||
if (command == 0x0036) {
|
||||
// A particular sector was requested
|
||||
printf("\x1b[32mSNES MSU: Sector requested\n\x1b[0m");
|
||||
msu_sector_requested = 1;
|
||||
}
|
||||
|
||||
has_command = 0;
|
||||
}
|
||||
|
||||
// Detect incoming command via CD_GET (which we are repurposing for MSU1)
|
||||
uint8_t req = spi_uio_cmd_cont(UIO_CD_GET);
|
||||
if (req != last_req)
|
||||
{
|
||||
last_req = req;
|
||||
|
||||
// 49 bit messaging (48 usable)
|
||||
uint16_t data_in[4];
|
||||
data_in[0] = spi_w(0);
|
||||
data_in[1] = spi_w(0);
|
||||
data_in[2] = spi_w(0);
|
||||
DisableIO();
|
||||
|
||||
if (need_reset || data_in[0] == 0xFF) {
|
||||
printf("SNES: request to reset\n");
|
||||
need_reset = 1;
|
||||
// TODO need to reset everything at this point
|
||||
need_reset = 0;
|
||||
//cdd.Reset();
|
||||
}
|
||||
|
||||
has_command = 1;
|
||||
command = data_in[0];
|
||||
command_payload_lower = data_in[1];
|
||||
command_payload_middle = data_in[2];
|
||||
command_payload_upper = data_in[3];
|
||||
|
||||
//printf("\x1b[32mSNES MSU: Get command, full command = %04X%04X%04X, has_command = %u\n\x1b[0m", data_in[2], data_in[1], data_in[0], has_command);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
// New MSU1 Track?
|
||||
if (msu_trackrequest == 1 && msu_trackmounted == 0)
|
||||
{
|
||||
send_sector = 0;
|
||||
// Track number is in the first word
|
||||
msu_trackout = command_payload_lower;
|
||||
printf("SNES MSU - New track selected: 0x%X\n", msu_trackout);
|
||||
msu_currenttrack = msu_trackout;
|
||||
|
||||
sprintf(SelectedPath, "%s-%d.pcm", snes_romFileName, msu_trackout);
|
||||
printf("SNES MSU - Full MSU track path is: %s\n", SelectedPath);
|
||||
|
||||
if (strlen(snes_romFileName) == 0)
|
||||
{
|
||||
printf(msuErrorMessage, "SNES MSU - No romname\nReload the rom or core");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FileOpen(&f, SelectedPath))
|
||||
{
|
||||
snes_msu_send_command(MSU_AUDIO_TRACKMISSING);
|
||||
sprintf(msuErrorMessage, "SNES MSU - Track not found: %d\n", 1);
|
||||
printf(msuErrorMessage, 3000);
|
||||
msu_trackrequest = 0;
|
||||
msu_trackmounted = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Track wasn't missing! Let's mount it and wait for sector requests
|
||||
user_io_file_mount(SelectedPath, 2);
|
||||
FileSeek(&f, 0, SEEK_SET);
|
||||
msu_trackmounted = 1;
|
||||
msu_trackrequest = 0;
|
||||
// Note that track request will be set to 0 AFTER the track mounted message is sent to FPGA
|
||||
printf("SNES MSU - Track mounted\n");
|
||||
msu_trackmissing = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msu_trackmounted == 1 && msu_trackrequest == 0 && send_sector == 1)
|
||||
{
|
||||
if (msu_sector_jumping == 1) {
|
||||
printf("SNES MSU - Sending a sector as part of a jump\n");
|
||||
msu_sector_jumping = 0;
|
||||
}
|
||||
|
||||
snes_msu_send_data(&f, buf);
|
||||
|
||||
msu_sector_jumping = 0;
|
||||
send_sector = 0;
|
||||
data_req = !data_req;
|
||||
}
|
||||
else if (msu_trackmounted == 1 && msu_trackrequest == 1 && send_sector == 0)
|
||||
{
|
||||
// Tell the core that the track has been mounted
|
||||
msu_trackrequest = 0;
|
||||
printf("SNES MSU: sending track mounted - 201\n");
|
||||
// @todo We may need to buffer on the linux side at this point
|
||||
snes_msu_send_command(MSU_AUDIO_TRACKMOUNTED);
|
||||
send_sector = 0;
|
||||
}
|
||||
else if (msu_trackmounted == 1 && msu_sector_requested == 1 && send_sector == 0)
|
||||
{
|
||||
// We received a jump sector message
|
||||
msu_sector_requested = 0;
|
||||
send_sector = 1;
|
||||
msu_sector_jumping = 1;
|
||||
snes_msu_jump_sector(&f, command_payload_middle << 8 | command_payload_lower);
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,10 @@
|
||||
|
||||
uint8_t* snes_get_header(fileTYPE *f);
|
||||
void snes_patch_bs_header(fileTYPE *f, uint8_t *buf);
|
||||
void snes_msu_init(const char* name);
|
||||
void snes_send_command(uint64_t);
|
||||
char* snes_read_track_out(void);
|
||||
int snes_send_data(void);
|
||||
void snes_poll(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2573,6 +2573,13 @@ int user_io_file_tx(const char* name, unsigned char index, char opensave, char m
|
||||
}
|
||||
|
||||
ProgressMessage(0, 0, 0, 0);
|
||||
|
||||
if (is_snes())
|
||||
{
|
||||
// Setup MSU
|
||||
snes_msu_init(name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2819,6 +2826,7 @@ void user_io_poll()
|
||||
else if ((core_type == CORE_TYPE_8BIT) && !is_menu() && !is_minimig())
|
||||
{
|
||||
if (is_st()) tos_poll();
|
||||
if (is_snes()) snes_poll();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user