cdc: get TOC

This commit is contained in:
Zack Buhman 2024-09-19 15:38:49 -05:00
parent 8f9fb2c7d7
commit 063699b4b3
4 changed files with 319 additions and 0 deletions

209
cdc/cdc.cpp Normal file
View File

@ -0,0 +1,209 @@
#include <stdint.h>
#include "sh2.h"
#include "serial.h"
volatile uint16_t * const DATATRNS = (volatile uint16_t *)0x25890000; // 0
volatile uint16_t * const DATASTAT = (volatile uint16_t *)0x25890004; // 1 (not implemented in mednafen)
volatile uint16_t * const HIRQREQ = (volatile uint16_t *)0x25890008; // 2
volatile uint16_t * const HIRQMSK = (volatile uint16_t *)0x2589000c; // 3
volatile uint16_t * const CDATA0 = (volatile uint16_t *)0x25890018; // 6
volatile uint16_t * const CDATA1 = (volatile uint16_t *)0x2589001c; // 7
volatile uint16_t * const CDATA2 = (volatile uint16_t *)0x25890020; // 8
volatile uint16_t * const CDATA3 = (volatile uint16_t *)0x25890024; // 9
volatile uint16_t * const MPEGRGB = (volatile uint16_t *)0x25890028; // a (not implemented in mednafen)
/* Bit names of interrupt factor registers (HIRQREQ, HIRQMSK) */
#define HIRQ__CMOK (1 << 0) /* Command can be issued */
#define HIRQ__DRDY (1 << 1) /* Data transfer ready */
#define HIRQ__CSCT (1 << 2) /* 1 sector read completed */
#define HIRQ__BFUL (1 << 3) /* CD buffer full */
#define HIRQ__PEND (1 << 4) /* End of CD playback */
#define HIRQ__DCHG (1 << 5) /* Disk replacement occurrence */
#define HIRQ__ESEL (1 << 6) /* End of selector setting process */
#define HIRQ__EHST (1 << 7) /* End of host I/O processing */
#define HIRQ__ECPY (1 << 8) /* End of copy/move processing */
#define HIRQ__EFLS (1 << 9) /* End of file system processing */
#define HIRQ__SCDQ (1 << 10) /* Subcode Q update completed */
#define HIRQ__MPED (1 << 11) /* End of MPEG-related processing */
#define HIRQ__MPCM (1 << 12) /* End of MPEG operation undefined interval */
#define HIRQ__MPST (1 << 13) /* MPEG interrupt status notification */
struct cd_command {
uint16_t CDATA[4];
};
struct cd_response {
uint16_t CDATA[4];
};
int cd_wait_hirq(uint16_t status)
{
for (int i = 0; i < 0x240000; i++) {
uint16_t hirq_temp = *HIRQREQ;
if ((hirq_temp & status) != 0) {
return 0;
}
}
return -1;
}
int cd_command_response(cd_command * command, cd_response * response)
{
uint16_t hirq = *HIRQREQ;
serial_string("cd_command_response hirq: ");
serial_integer(hirq, 8, '\n');
if ((hirq & HIRQ__CMOK) == 0) {
return -1;
}
*HIRQREQ &= ~HIRQ__CMOK;
*CDATA0 = command->CDATA[0];
*CDATA1 = command->CDATA[1];
*CDATA2 = command->CDATA[2];
*CDATA3 = command->CDATA[3];
if (cd_wait_hirq(HIRQ__CMOK) != 0) {
return -1;
}
response->CDATA[0] = *CDATA0;
response->CDATA[1] = *CDATA1;
response->CDATA[2] = *CDATA2;
response->CDATA[3] = *CDATA3;
return 0;
}
int cd_data_end()
{
struct cd_command command = {{
0x0600,
0,
0,
0
}};
struct cd_response response = {0};
int ret = cd_command_response(&command, &response);
*HIRQREQ &= ~HIRQ__DRDY;
return ret;
}
int cd_wait_data_ready()
{
int ret = cd_wait_hirq(HIRQ__DRDY);
if (ret != 0)
cd_data_end();
*HIRQREQ &= ~HIRQ__DRDY;
return ret;
}
int cd_get_data(uint16_t * data, int size)
{
int ret;
ret = cd_wait_data_ready();
if (ret != 0)
return -1;
while (size > 0) {
*data = *DATATRNS;
data += 1;
size -= 1;
}
ret = cd_data_end();
if (ret != 0)
return -1;
return 0;
}
int cd_get_toc(uint32_t * toc)
{
struct cd_command command = {{
0x0200,
0,
0,
0
}};
struct cd_response response = {0};
int ret = cd_command_response(&command, &response);
if (ret != 0)
return -1;
int size = ((response.CDATA[0] & 0xff) << 16)
| ((response.CDATA[1] & 0xffff) << 0);
ret = cd_get_data((uint16_t *)toc, size);
if (ret != 0)
return -1;
return 0;
}
int cd_init()
{
struct cd_command command = {{
0x0400,
0,
0,
0x040f,
}};
struct cd_response response = {0};
int ret = cd_command_response(&command, &response);
return ret;
}
void test_cd()
{
int ret;
ret = cd_init();
serial_string("cd_init: ");
serial_integer(ret, 8, '\n');
if (ret != 0)
return;
uint32_t toc[102];
ret = cd_get_toc(toc);
serial_string("cd_get_toc: ");
serial_integer(ret, 8, '\n');
if (ret != 0)
return;
for (int i = 0; i < 102; i++) {
serial_integer(toc[i], 8, '\n');
}
}
void main()
{
// serial mode register
sh2.reg.SMR = 0
| SMR__CA__ASYNCHRONOUS_MODE
| SMR__CHR__EIGHT_BIT_DATA
| SMR__PE__PARITY_BIT_NOT_ADDED_OR_CHECKED
| SMR__OE__EVEN_PARITY
| SMR__STOP__ONE_STOP_BIT
| SMR__MP__DISABLED
| SMR__CKS__PHI_4;
// actual baud rate at phi_4 = 3579545 / (16 * (5 + 1))
// 37286.927 ~= 38400
sh2.reg.BRR = 5;
sh2.reg.SCR = SCR__TE__TRANSMITTER_ENABLE | SCR__RE__RECEIVER_ENABLE;
sh2.reg.SSR = 0;
test_cd();
while (1);
}

50
cdc/serial.c Normal file
View File

@ -0,0 +1,50 @@
#include "serial.h"
#include "sh2.h"
void serial_char(const char c)
{
while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
sh2.reg.TDR = c;
}
void serial_string(const char * s)
{
while (*s) {
while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
sh2.reg.TDR = *s++;
}
}
void serial_bytes(const char * s, uint32_t length)
{
while (length > 0) {
while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
sh2.reg.TDR = *s++;
length -= 1;
}
}
static void hex(char * c, uint32_t len, uint32_t n)
{
while (len > 0) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
c[--len] = nib;
}
}
void serial_integer(const uint32_t n, const uint32_t length, const char end)
{
char num_buf[length];
hex(num_buf, length, n);
serial_string("0x");
serial_bytes(num_buf, length);
serial_char(end);
}

16
cdc/serial.h Normal file
View File

@ -0,0 +1,16 @@
#include <stdint.h>
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void serial_char(const char c);
void serial_string(const char * s);
void serial_bytes(const char * s, uint32_t length);
void serial_integer(const uint32_t n, const uint32_t length, const char end);
#ifdef __cplusplus
}
#endif

44
cdc/toc.h Normal file
View File

@ -0,0 +1,44 @@
#include <stdint.h>
struct track {
const uint8_t control_adr;
const uint8_t fad[3];
};
static_assert((sizeof (track)) == 4);
struct start_track {
const uint8_t control_adr;
const uint8_t start_track_number;
const uint8_t _zero[2];
};
static_assert((sizeof (start_track)) == 4);
struct end_track {
const uint8_t control_adr;
const uint8_t end_track_number;
const uint8_t _zero[2];
};
static_assert((sizeof (end_track)) == 4);
struct toc {
struct track track[99];
struct start_track start_track;
struct end_track end_track;
struct track lead_out;
};
static_assert((sizeof (toc)) == 408);
uint32_t track_fad(struct track * t) const
{
return (t->fad[0] << 16) | (t->fad[1] << 8) | (t->fad[2] << 0);
}
uint8_t track_control(struct track * t) const
{
return (t->control_adr >> 4) & 0xf;
}
uint8_t track_adr(struct track * t) const
{
return (t->control_adr >> 0) & 0xf;
}