1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-01-11 23:43:04 +00:00

Add PSX CD support

This commit is contained in:
Gyorgy Szombathelyi 2024-03-10 16:42:14 +01:00
parent ceb1fc0271
commit 9d7f44b10b
9 changed files with 290 additions and 56 deletions

View File

@ -12,7 +12,7 @@ TODAY = `date +"%m/%d/%y"`
PRJ = firmware
SRC = hw/ATSAMV71/cstartup.c hw/ATSAMV71/hardware.c hw/ATSAMV71/spi.c hw/ATSAMV71/qspi.c hw/ATSAMV71/mmc.c hw/ATSAMV71/usbdev.c hw/ATSAMV71/eth.c hw/ATSAMV71/irq/nvic.c
SRC += hw/ATSAMV71/network/intmath.c hw/ATSAMV71/network/gmac.c hw/ATSAMV71/network/gmacd.c hw/ATSAMV71/network/phy.c hw/ATSAMV71/network/ethd.c
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c menu-minimig.c menu-8bit.c osd.c state.c syscalls.c user_io.c settings.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c neocd.c arc_file.c font.c utils.c
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c menu-minimig.c menu-8bit.c osd.c state.c syscalls.c user_io.c settings.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c neocd.c psx.c arc_file.c font.c utils.c
SRC += it6613/HDMI_TX.c it6613/it6613_drv.c it6613/it6613_sys.c it6613/EDID.c it6613/hdmitx_mist.c
SRC += usb/usbdebug.c usb/hub.c usb/xboxusb.c usb/hid.c usb/hidparser.c usb/timer.c usb/asix.c usb/pl2303.c usb/usbrtc.c usb/joymapping.c usb/joystick.c
SRC += usb/usb.c usb/max3421e.c usb/usb-max3421e.c
@ -30,7 +30,7 @@ LIBDIR =
# Commandline options for each tool.
# for ESA11 add -DEMIST
DFLAGS = -I. -Iarch -Icmsis -Iusb -Ihw/ATSAMV71 -DMIST -DCONFIG_HAVE_NVIC -DCONFIG_HAVE_ETH -DCONFIG_HAVE_GMAC -DCONFIG_HAVE_GMAC_QUEUES -DGMAC_QUEUE_COUNT=6 -DCONFIG_ARCH_ARM -DCONFIG_ARCH_ARMV7M -DCONFIG_CHIP_SAMV71 -DCONFIG_PACKAGE_100PIN
DFLAGS += -DFW_ID=\"SIDIUPG\" -DDEFAULT_CORE_NAME=\"SIDI128.RBF\" -DFATFS_NO_TINY -DSD_NO_DIRECT_MODE -DJOY_DB9_MD -DHAVE_QSPI -DHAVE_HDMI
DFLAGS += -DFW_ID=\"SIDIUPG\" -DDEFAULT_CORE_NAME=\"SIDI128.RBF\" -DFATFS_NO_TINY -DSD_NO_DIRECT_MODE -DJOY_DB9_MD -DHAVE_QSPI -DHAVE_HDMI -DHAVE_PSX
#DFLAGS += -DPROTOTYPE
CFLAGS = $(DFLAGS) -march=armv7-m -mtune=cortex-m7 -mthumb -ffunction-sections -fsigned-char -c -g -O2 --std=gnu99 -DVDATE=\"`date +"%y%m%d"`\"
CFLAGS += $(CFLAGS-$@)

View File

@ -21,6 +21,33 @@ void data_io_set_index(char index) {
DisableFpga();
}
void data_io_file_tx_start(void) {
EnableFpga();
SPI(DIO_FILE_TX);
SPI(0xff);
DisableFpga();
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI)
qspi_start_write();
#endif
}
void data_io_file_tx_done(void) {
// signal end of transmission
EnableFpga();
SPI(DIO_FILE_TX);
SPI(0x00);
DisableFpga();
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI)
qspi_end();
#endif
iprintf("\n");
}
///////////////////////////
// TRANSMIT FILE TO FPGA //
///////////////////////////
@ -61,16 +88,8 @@ static void data_io_file_tx_prepare(FIL *file, char index, const char *ext) {
DisableFpga();
// prepare transmission of new file
data_io_file_tx_start();
EnableFpga();
SPI(DIO_FILE_TX);
SPI(0xff);
DisableFpga();
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI)
qspi_start_write();
#endif
}
static void data_io_file_tx_send(FIL *file) {
@ -120,20 +139,6 @@ static void data_io_file_tx_send(FIL *file) {
}
}
static void data_io_file_tx_done(void) {
// signal end of transmission
EnableFpga();
SPI(DIO_FILE_TX);
SPI(0x00);
DisableFpga();
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI)
qspi_end();
#endif
iprintf("\n");
}
static void data_io_file_tx_fill(unsigned char fill, unsigned int len) {

View File

@ -17,6 +17,8 @@
#define DIO_FILE_RX_DAT 0x58
void data_io_set_index(char index);
void data_io_file_tx_start();
void data_io_file_tx_done();
void data_io_fill_tx(unsigned char, unsigned int, char);
void data_io_file_tx(FIL*, char, const char*);
void data_io_file_rx(FIL*, char, unsigned int);

View File

@ -154,6 +154,13 @@
#define neocd_debugf(...)
#endif
#if 0
// PSX debug output
#define psx_debugf(a, ...) iprintf("\033[1;34mPSX : " a "\033[0m\n",## __VA_ARGS__)
#else
#define psx_debugf(...)
#endif
#if 1
// HDMI debug output
#define hdmi_debugf(a, ...) iprintf("\033[1;34mHDMI : " a "\033[0m",## __VA_ARGS__)

View File

@ -40,14 +40,14 @@ typedef struct
extern IDXFile sd_image[SD_IMAGES];
static inline unsigned char IDXRead(IDXFile *file, unsigned char *pBuffer) {
static inline unsigned char IDXRead(IDXFile *file, unsigned char *pBuffer, uint8_t blksz) {
UINT br;
return f_read(&(file->file), pBuffer, 512, &br);
return f_read(&(file->file), pBuffer, 512<<blksz, &br);
}
static inline unsigned char IDXWrite(IDXFile *file, unsigned char *pBuffer) {
static inline unsigned char IDXWrite(IDXFile *file, unsigned char *pBuffer, uint8_t blksz) {
UINT bw;
return f_write(&(file->file), pBuffer, 512, &bw);
return f_write(&(file->file), pBuffer, 512<<blksz, &bw);
}
unsigned char IDXOpen(IDXFile *file, const char *name, char mode);

195
psx.c Normal file
View File

@ -0,0 +1,195 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "psx.h"
#include "cue_parser.h"
#include "user_io.h"
#include "data_io.h"
#include "utils.h"
#include "debug.h"
typedef enum
{
UNKNOWN = 0,
JP,
US,
EU
} region_t;
static char *region_str[] = {"Unknown", "JP", "US", "EU"};
typedef struct
{
uint32_t track_count;
uint32_t total_lba;
uint32_t total_bcd;
uint16_t libcrypt_mask;
uint16_t metadata; // lower 2 bits encode the region, 3rd bit is reset request, the other bits are reseved
} __attribute__ ((packed)) disk_header_t;
typedef struct
{
uint32_t start_lba;
uint32_t end_lba;
uint32_t bcd;
uint32_t reserved;
} __attribute__ ((packed)) track_t;
#define SBI_HEADER_SIZE 4
#define SBI_BLOCK_SIZE 14
static uint32_t libCryptSectors[16] =
{
14105,
14231,
14485,
14579,
14649,
14899,
15056,
15130,
15242,
15312,
15378,
15628,
15919,
16031,
16101,
16167,
};
static uint16_t psx_libCryptMask(FIL* sbi_file)
{
UINT br;
uint16_t mask = 0;
if ((f_read(sbi_file, sector_buffer, SECTOR_BUFFER_SIZE, &br)) == FR_OK)
{
for (int i = 0;; i++)
{
int pos = SBI_HEADER_SIZE + i * SBI_BLOCK_SIZE;
if (pos >= br) break;
uint32_t lba = 150 + MSF2LBA(bcd2bin(sector_buffer[pos]), bcd2bin(sector_buffer[pos + 1]), bcd2bin(sector_buffer[pos + 2]));
psx_debugf("Testing lba from SBI: %d", lba);
for (int m = 0; m < 16; m++) if (libCryptSectors[m] == lba) mask |= (1 << (15 - m));
}
}
return mask;
}
static void psx_read_sector(char* buffer, unsigned int lba)
{
UINT br;
if (!toc.valid) {
memset(buffer, 0, 2352);
return;
}
int index = cue_gettrackbylba(lba);
int offset = (lba - toc.tracks[index].start) * toc.tracks[index].sector_size + toc.tracks[index].offset;
//psx_debugf("read CD lba=%d, track=%d offset=%d (trackstart=%d tracoffset=%d tracksectorsize=%d)", lba, index, offset, toc.tracks[index].start, toc.tracks[index].offset, toc.tracks[index].sector_size);
if (toc.tracks[index].sector_size != 2352) {
// unsupported sector size by the core
memset(buffer, 0, 2352);
} else {
DISKLED_ON
f_lseek(&toc.file->file, offset);
f_read(&toc.file->file, buffer, 2352, &br);
DISKLED_OFF
}
return;
}
static void psx_send_cue_and_metadata(uint16_t libcrypt_mask, region_t region, int reset)
{
disk_header_t header;
track_t track;
msf_t msf;
header.track_count = (bin2bcd(toc.last) << 8) | toc.last;
header.total_lba = toc.end;
LBA2MSF(toc.end, &msf);
header.total_bcd = (bin2bcd(msf.m) << 8) | bin2bcd(msf.s);
header.libcrypt_mask = libcrypt_mask;
header.metadata = region; // the lower 2 bits of metadata contain the region
if (reset) header.metadata |= 4; // 3rd bit is reset request
data_io_set_index(251);
data_io_file_tx_start();
EnableFpga();
SPI(DIO_FILE_TX_DAT);
spi_write((const char *)&header, sizeof(disk_header_t));
track.reserved = 0;
for (int i = 0; i < toc.last; i++) {
track.start_lba = toc.tracks[i].start;
track.end_lba = toc.tracks[i].end;
LBA2MSF(toc.tracks[i].start, &msf);
track.bcd = ((bin2bcd(msf.m) << 8) | bin2bcd(msf.s)) | ((toc.tracks[i].type ? 0 : 1) << 16);
psx_debugf("%d start_lba=%d end_lba=%d bcd=%04x", i, track.start_lba, track.end_lba, track.bcd);
spi_write((const char *)&track, sizeof(track_t));
}
DisableFpga();
data_io_file_tx_done();
}
static region_t psx_get_region()
{
int license_sector = 4;
psx_read_sector(sector_buffer, license_sector);
uint8_t* license_start = (uint8_t*)memmem(sector_buffer, 2352, " Licensed by Sony Computer Entertainment ", 60);
if (license_start) {
const uint8_t* region_start = license_start + 60;
if (memcmp(region_start, "Amer ica ", 10) == 0)
return US;
if (memcmp(region_start, "Inc.", 4) == 0)
return JP;
if (memcmp(region_start, "Euro pe", 7) == 0)
return EU;
}
return UNKNOWN;
}
void psx_mount_cd(const unsigned char *name)
{
if (!toc.valid) return;
region_t region = psx_get_region();
uint16_t libcrypt_mask = 0;
const char *fileExt = 0;
int len = strlen(name);
while(len > 2) {
if (name[len-2] == '.') {
fileExt = &name[len-1];
break;
}
len--;
}
if (fileExt) {
char sbi[len+3];
memcpy(sbi, name, len-1);
strcpy(&sbi[len-1], "SBI");
FIL sbi_f;
iprintf("PSX: trying SBI file (%s)\n", sbi);
if(f_open(&sbi_f, sbi, FA_READ) == FR_OK) {
libcrypt_mask = psx_libCryptMask(&sbi_f);
f_close(&sbi_f);
}
}
iprintf("PSX: CD region: %s crypt_mask: %04x\n", region_str[region], libcrypt_mask);
psx_send_cue_and_metadata(libcrypt_mask, region, 0);
}
void psx_read_cd(uint8_t drive_index, unsigned int lba)
{
user_io_sd_ack(drive_index);
if (lba>=150) lba-=150;
psx_read_sector(sector_buffer, lba);
spi_uio_cmd_cont(UIO_SECTOR_RD);
spi_write(sector_buffer, 2352);
DisableIO();
}

9
psx.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _PSX_H_
#define _PSX_H_
#include <stdint.h>
void psx_mount_cd(const unsigned char *name);
void psx_read_cd(uint8_t drive_index, unsigned int lba);
#endif

View File

@ -11,6 +11,7 @@
#include "archie.h"
#include "pcecd.h"
#include "neocd.h"
#include "psx.h"
#include "hdd.h"
#include "cdc_control.h"
#include "usb.h"
@ -42,7 +43,7 @@ unsigned char key_remap_table[MAX_REMAP][2];
#define BREAK 0x8000
static char umounted; // 1st image is file or direct SD?
static char buffer[512];
static char cache_buffer[1024];
static uint8_t buffer_drive_index = 0;
static uint32_t buffer_lba = 0xffffffff;
@ -629,21 +630,26 @@ void user_io_sd_set_config(void) {
// hexdump(data, sizeof(data), 0);
}
static void user_io_sd_ack(char drive_index) {
void user_io_sd_ack(char drive_index) {
spi_uio_cmd_cont(UIO_SD_ACK);
spi8(drive_index);
DisableIO();
}
// read 8+32 bit sd card status word from FPGA
uint8_t user_io_sd_get_status(uint32_t *lba, uint8_t *drive_index) {
uint8_t user_io_sd_get_status(uint32_t *lba, uint8_t *drive_index, uint8_t *blksz) {
uint32_t s;
uint8_t c;
*drive_index = 0;
*blksz = 0;
spi_uio_cmd_cont(UIO_GET_SDSTAT);
c = spi_in();
if ((c & 0xf0) == 0x60) *drive_index = spi_in() & 0x03;
if ((c & 0xf0) == 0x60) {
uint8_t tmp = spi_in();
*drive_index = tmp & 0x03;
*blksz = (tmp >> 4) & 0x01;
}
s = spi_in();
s = (s<<8) | spi_in();
s = (s<<8) | spi_in();
@ -784,7 +790,9 @@ char user_io_cue_mount(const unsigned char *name, unsigned char index) {
if (name) {
res = cue_parse(name, &sd_image[index]);
}
#ifdef HAVE_PSX
if (core_features & FEAT_PSX) psx_mount_cd(name);
#endif
// send mounted image size first then notify about mounting
EnableIO();
SPI(UIO_SET_SDINFO);
@ -1450,7 +1458,8 @@ void user_io_poll() {
{
uint32_t lba;
uint8_t drive_index;
uint8_t c = user_io_sd_get_status(&lba, &drive_index);
uint8_t blksz;
uint8_t c = user_io_sd_get_status(&lba, &drive_index, &blksz);
// valid sd commands start with "5x" (old API), or "6x" (new API)
// to avoid problems with cores that don't implement this command
@ -1499,10 +1508,8 @@ void user_io_poll() {
// only write if the inserted card is not sdhc or
// if the core uses sdhc
if((!MMC_IsSDHC()) || (c & 0x04)) {
uint8_t wr_buf[512];
if(user_io_dip_switch1())
iprintf("SD WR (%d) %d\n", drive_index, lba);
iprintf("SD WR (%d) %d/%d\n", drive_index, lba, 512<<blksz);
// if we write the sector stored in the read buffer, then
// invalidate the cache
@ -1512,7 +1519,7 @@ void user_io_poll() {
user_io_sd_ack(drive_index);
// Fetch sector data from FPGA ...
spi_uio_cmd_cont(UIO_SECTOR_WR);
spi_block_read(wr_buf);
spi_read(sector_buffer, 512<<blksz);
DisableIO();
// ... and write it to disk
@ -1520,14 +1527,14 @@ void user_io_poll() {
#if 1
if(sd_image[sd_index(drive_index)].valid) {
if(((f_size(&sd_image[sd_index(drive_index)].file)-1) >> 9) >= lba) {
IDXSeek(&sd_image[sd_index(drive_index)], lba);
IDXWrite(&sd_image[sd_index(drive_index)], wr_buf);
if(((f_size(&sd_image[sd_index(drive_index)].file)-1) >> (9+blksz)) >= lba) {
IDXSeek(&sd_image[sd_index(drive_index)], (lba<<blksz));
IDXWrite(&sd_image[sd_index(drive_index)], sector_buffer, blksz);
}
} else if (!drive_index && !umounted)
disk_write(fs.pdrv, wr_buf, lba, 1);
disk_write(fs.pdrv, sector_buffer, lba, 1<<blksz);
#else
hexdump(wr_buf, 512, 0);
hexdump(sector_buffer, 32, 0);
#endif
DISKLED_OFF;
@ -1538,37 +1545,41 @@ void user_io_poll() {
if((c & 0x03) == 0x01) {
if(user_io_dip_switch1())
iprintf("SD RD (%d) %d\n", drive_index, lba);
iprintf("SD RD (%d) %d/%d\n", drive_index, lba, 512<<blksz);
// invalidate cache if it stores data from another drive
if (drive_index != buffer_drive_index)
buffer_lba = 0xffffffff;
#ifdef HAVE_PSX
if ((core_features & FEAT_PSX) && drive_index == 1) {
psx_read_cd(drive_index, lba);
} else {
#endif
// are we using a file as the sd card image?
// (C64 floppy does that ...)
if(buffer_lba != lba) {
DISKLED_ON;
if(sd_image[sd_index(drive_index)].valid) {
if(((f_size(&sd_image[sd_index(drive_index)].file)-1) >> 9) >= lba) {
IDXSeek(&sd_image[sd_index(drive_index)], lba);
IDXRead(&sd_image[sd_index(drive_index)], buffer);
if(((f_size(&sd_image[sd_index(drive_index)].file)-1) >> (9+blksz)) >= lba) {
IDXSeek(&sd_image[sd_index(drive_index)], lba<<blksz);
IDXRead(&sd_image[sd_index(drive_index)], cache_buffer, blksz);
}
} else if (!drive_index && !umounted) {
// sector read
// read sector from sd card if it is not already present in
// the buffer
disk_read(fs.pdrv, buffer, lba, 1);
disk_read(fs.pdrv, cache_buffer, lba, 1<<blksz);
}
buffer_lba = lba;
DISKLED_OFF;
}
if(buffer_lba == lba) {
// hexdump(buffer, 32, 0);
// hexdump(cache_buffer, 512<<blksz, 0);
user_io_sd_ack(drive_index);
// data is now stored in buffer. send it to fpga
spi_uio_cmd_cont(UIO_SECTOR_RD);
spi_block_write(buffer);
spi_write(cache_buffer, 512<<blksz);
DisableIO();
// the end of this transfer acknowledges the FPGA internal
@ -1580,20 +1591,23 @@ void user_io_poll() {
DISKLED_ON;
if(sd_image[sd_index(drive_index)].valid) {
// but check if it would overrun on the file
if(((f_size(&sd_image[sd_index(drive_index)].file)-1) >> 9) > lba) {
IDXSeek(&sd_image[sd_index(drive_index)], lba+1);
IDXRead(&sd_image[sd_index(drive_index)], buffer);
if(((f_size(&sd_image[sd_index(drive_index)].file)-1) >> (9+blksz)) > lba) {
IDXSeek(&sd_image[sd_index(drive_index)], (lba+1)<<blksz);
IDXRead(&sd_image[sd_index(drive_index)], cache_buffer, blksz);
buffer_lba = lba + 1;
}
} else {
// sector read
// read sector from sd card if it is not already present in
// the buffer
disk_read(fs.pdrv, buffer, lba+1, 1);
disk_read(fs.pdrv, cache_buffer, lba+1, 1<<blksz);
buffer_lba = lba+1;
}
buffer_drive_index = drive_index;
DISKLED_OFF;
#ifdef HAVE_PSX
}
#endif
}
}
}

View File

@ -103,6 +103,7 @@
#define FEAT_PS2REP 0x1000 // typematic repeat by default
#define FEAT_BIGOSD 0x2000 // 16 line tall OSD
#define FEAT_HDMI 0x4000 // HDMI output
#define FEAT_PSX 0x8000 // PSX-specific CD image handling
#define JOY_RIGHT 0x01
#define JOY_LEFT 0x02
@ -218,6 +219,7 @@ char user_io_is_cue_mounted();
char user_io_cue_mount(const unsigned char*, unsigned char);
char *user_io_get_core_name();
void user_io_set_core_mod(char);
void user_io_sd_ack(char drive_index);
// io controllers interface for FPGA ethernet emulation using usb ethernet
// devices attached to the io controller (ethernec emulation)