mirror of
https://github.com/MiSTer-devel/CDi_MiSTer.git
synced 2026-04-19 03:04:19 +00:00
- MPEG video decoder based on pl_mpeg, executed on 3 VexiiRiscv cores. One for decoding the stream and two for pixel workings and IDCT. - Added additional clock for MPEG workers - Added hardware accelerated DCT coefficient huffman decoder - Generalized MPEG demuxer design for video and audio - Removed fake startcode decoder for video stream (for now) - Expanded Verilator testbench with YUV to RGB conversion to extract decoded MPEG frames - Dragon's Lair Intro can be decoded with this (vmpeg.asm) Design cannot be synthesized
1287 lines
53 KiB
C++
1287 lines
53 KiB
C++
// Include common routines
|
|
#include <verilated.h>
|
|
#include <verilated_fst_c.h>
|
|
#include <verilated_vcd_c.h>
|
|
|
|
// Include model header, generated from Verilating "top.v"
|
|
#include "Vemu.h"
|
|
#include "Vemu___024root.h"
|
|
|
|
#include <chrono>
|
|
#include <csignal>
|
|
#include <cstdint>
|
|
#include <png.h>
|
|
|
|
#include "hle.h"
|
|
#include <arpa/inet.h>
|
|
#include <byteswap.h>
|
|
|
|
#define SCC68070
|
|
#define SLAVE
|
|
// #define TRACE
|
|
// #define SIMULATE_RC5
|
|
|
|
#define PL_MPEG_IMPLEMENTATION
|
|
#include "pl_mpeg_pc.h"
|
|
|
|
int write_bmp(const char *path, int width, int height, uint8_t *pixels) {
|
|
FILE *fh = fopen(path, "wb");
|
|
if (!fh) {
|
|
return 0;
|
|
}
|
|
|
|
int padded_width = (width * 3 + 3) & (~3);
|
|
int padding = padded_width - (width * 3);
|
|
int data_size = padded_width * height;
|
|
int file_size = 54 + data_size;
|
|
|
|
fwrite("BM", 1, 2, fh);
|
|
fwrite(&file_size, 1, 4, fh);
|
|
fwrite("\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00", 1, 12, fh);
|
|
fwrite(&width, 1, 4, fh);
|
|
fwrite(&height, 1, 4, fh);
|
|
fwrite("\x01\x00\x18\x00\x00\x00\x00\x00", 1, 8, fh); // planes, bpp, compression
|
|
fwrite(&data_size, 1, 4, fh);
|
|
fwrite("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 1, 16, fh);
|
|
|
|
for (int y = height - 1; y >= 0; y--) {
|
|
fwrite(pixels + y * width * 3, 3, width, fh);
|
|
fwrite("\x00\x00\x00\x00", 1, padding, fh);
|
|
}
|
|
fclose(fh);
|
|
return file_size;
|
|
}
|
|
|
|
typedef struct {
|
|
unsigned int width;
|
|
unsigned int height;
|
|
uint32_t adr;
|
|
} plm_plane2_t;
|
|
|
|
typedef struct {
|
|
int32_t time;
|
|
unsigned int width;
|
|
unsigned int height;
|
|
plm_plane2_t y;
|
|
plm_plane2_t cr;
|
|
plm_plane2_t cb;
|
|
} plm_frame2_t;
|
|
|
|
#define BCD(v) ((uint8_t)((((v) / 10) << 4) | ((v) % 10)))
|
|
|
|
struct subcode {
|
|
uint16_t control;
|
|
uint16_t track;
|
|
uint16_t index;
|
|
uint16_t mode1_mins;
|
|
uint16_t mode1_secs;
|
|
uint16_t mode1_frac;
|
|
uint16_t mode1_zero;
|
|
uint16_t mode1_amins;
|
|
uint16_t mode1_asecs;
|
|
uint16_t mode1_afrac;
|
|
uint16_t mode1_crc0;
|
|
uint16_t mode1_crc1;
|
|
};
|
|
static_assert(sizeof(struct subcode) == 24);
|
|
|
|
struct toc_entry {
|
|
uint8_t control;
|
|
uint8_t track;
|
|
uint8_t m;
|
|
uint8_t s;
|
|
uint8_t f;
|
|
};
|
|
|
|
static struct toc_entry toc_buffer[100];
|
|
int toc_entry_count = 0;
|
|
|
|
#ifdef TRACE
|
|
typedef VerilatedFstC tracetype_t;
|
|
|
|
static bool do_trace{true};
|
|
#endif
|
|
volatile sig_atomic_t status = 0;
|
|
|
|
const int width = 120 * 16;
|
|
const int height = 312;
|
|
const int size = width * height * 3;
|
|
|
|
FILE *f_cd_bin{nullptr};
|
|
|
|
template <typename T, typename U> constexpr T BIT(T x, U n) noexcept {
|
|
return (x >> n) & T(1);
|
|
}
|
|
|
|
bool press_button_signal{false};
|
|
|
|
void signal_handler(int signum, siginfo_t *info, void *context) {
|
|
fprintf(stderr, "Received signal %d\n", signum);
|
|
|
|
switch (signum) {
|
|
case SIGINT:
|
|
// End simulation
|
|
status = signum;
|
|
break;
|
|
case SIGUSR1:
|
|
// Press a button
|
|
press_button_signal = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// got from mame
|
|
uint32_t lba_from_time(uint32_t m_time) {
|
|
const uint8_t bcd_mins = (m_time >> 24) & 0xff;
|
|
const uint8_t mins_upper_digit = bcd_mins >> 4;
|
|
const uint8_t mins_lower_digit = bcd_mins & 0xf;
|
|
const uint8_t raw_mins = (mins_upper_digit * 10) + mins_lower_digit;
|
|
|
|
const uint8_t bcd_secs = (m_time >> 16) & 0xff;
|
|
const uint8_t secs_upper_digit = bcd_secs >> 4;
|
|
const uint8_t secs_lower_digit = bcd_secs & 0xf;
|
|
const uint8_t raw_secs = (secs_upper_digit * 10) + secs_lower_digit;
|
|
|
|
uint32_t lba = ((raw_mins * 60) + raw_secs) * 75;
|
|
|
|
const uint8_t bcd_frac = (m_time >> 8) & 0xff;
|
|
const bool even_second = BIT(bcd_frac, 7);
|
|
if (!even_second) {
|
|
const uint8_t frac_upper_digit = bcd_frac >> 4;
|
|
const uint8_t frac_lower_digit = bcd_frac & 0xf;
|
|
const uint8_t raw_frac = (frac_upper_digit * 10) + frac_lower_digit;
|
|
lba += raw_frac;
|
|
}
|
|
|
|
if (lba >= 150)
|
|
lba -= 150;
|
|
|
|
return lba;
|
|
}
|
|
|
|
// CRC routine from https://github.com/mamedev/mame/blob/master/src/mame/philips/cdicdic.cpp
|
|
const uint16_t s_crc_ccitt_table[256] = {
|
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad,
|
|
0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a,
|
|
0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
|
|
0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
|
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861,
|
|
0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
|
|
0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87,
|
|
0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
|
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
|
|
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3,
|
|
0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290,
|
|
0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
|
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e,
|
|
0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f,
|
|
0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
|
|
0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
|
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83,
|
|
0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
|
|
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
|
|
|
|
#define CRC_CCITT_ROUND(accum, data) (((accum << 8) | data) ^ s_crc_ccitt_table[accum >> 8])
|
|
|
|
// sector descrambling routine from https://github.com/mamedev/mame/blob/master/src/mame/philips/cdicdic.cpp
|
|
const uint8_t s_sector_scramble[] = {
|
|
0x01, 0x80, 0x00, 0x60, 0x00, 0x28, 0x00, 0x1e, 0x80, 0x08, 0x60, 0x06, 0xa8, 0x02, 0xfe, 0x81, 0x80, 0x60, 0x60,
|
|
0x28, 0x28, 0x1e, 0x9e, 0x88, 0x68, 0x66, 0xae, 0xaa, 0xfc, 0x7f, 0x01, 0xe0, 0x00, 0x48, 0x00, 0x36, 0x80, 0x16,
|
|
0xe0, 0x0e, 0xc8, 0x04, 0x56, 0x83, 0x7e, 0xe1, 0xe0, 0x48, 0x48, 0x36, 0xb6, 0x96, 0xf6, 0xee, 0xc6, 0xcc, 0x52,
|
|
0xd5, 0xfd, 0x9f, 0x01, 0xa8, 0x00, 0x7e, 0x80, 0x20, 0x60, 0x18, 0x28, 0x0a, 0x9e, 0x87, 0x28, 0x62, 0x9e, 0xa9,
|
|
0xa8, 0x7e, 0xfe, 0xa0, 0x40, 0x78, 0x30, 0x22, 0x94, 0x19, 0xaf, 0x4a, 0xfc, 0x37, 0x01, 0xd6, 0x80, 0x5e, 0xe0,
|
|
0x38, 0x48, 0x12, 0xb6, 0x8d, 0xb6, 0xe5, 0xb6, 0xcb, 0x36, 0xd7, 0x56, 0xde, 0xbe, 0xd8, 0x70, 0x5a, 0xa4, 0x3b,
|
|
0x3b, 0x53, 0x53, 0x7d, 0xfd, 0xe1, 0x81, 0x88, 0x60, 0x66, 0xa8, 0x2a, 0xfe, 0x9f, 0x00, 0x68, 0x00, 0x2e, 0x80,
|
|
0x1c, 0x60, 0x09, 0xe8, 0x06, 0xce, 0x82, 0xd4, 0x61, 0x9f, 0x68, 0x68, 0x2e, 0xae, 0x9c, 0x7c, 0x69, 0xe1, 0xee,
|
|
0xc8, 0x4c, 0x56, 0xb5, 0xfe, 0xf7, 0x00, 0x46, 0x80, 0x32, 0xe0, 0x15, 0x88, 0x0f, 0x26, 0x84, 0x1a, 0xe3, 0x4b,
|
|
0x09, 0xf7, 0x46, 0xc6, 0xb2, 0xd2, 0xf5, 0x9d, 0x87, 0x29, 0xa2, 0x9e, 0xf9, 0xa8, 0x42, 0xfe, 0xb1, 0x80, 0x74,
|
|
0x60, 0x27, 0x68, 0x1a, 0xae, 0x8b, 0x3c, 0x67, 0x51, 0xea, 0xbc, 0x4f, 0x31, 0xf4, 0x14, 0x47, 0x4f, 0x72, 0xb4,
|
|
0x25, 0xb7, 0x5b, 0x36, 0xbb, 0x56, 0xf3, 0x7e, 0xc5, 0xe0, 0x53, 0x08, 0x3d, 0xc6, 0x91, 0x92, 0xec, 0x6d, 0x8d,
|
|
0xed, 0xa5, 0x8d, 0xbb, 0x25, 0xb3, 0x5b, 0x35, 0xfb, 0x57, 0x03, 0x7e, 0x81, 0xe0, 0x60, 0x48, 0x28, 0x36, 0x9e,
|
|
0x96, 0xe8, 0x6e, 0xce, 0xac, 0x54, 0x7d, 0xff, 0x61, 0x80, 0x28, 0x60, 0x1e, 0xa8, 0x08, 0x7e, 0x86, 0xa0, 0x62,
|
|
0xf8, 0x29, 0x82, 0x9e, 0xe1, 0xa8, 0x48, 0x7e, 0xb6, 0xa0, 0x76, 0xf8, 0x26, 0xc2, 0x9a, 0xd1, 0xab, 0x1c, 0x7f,
|
|
0x49, 0xe0, 0x36, 0xc8, 0x16, 0xd6, 0x8e, 0xde, 0xe4, 0x58, 0x4b, 0x7a, 0xb7, 0x63, 0x36, 0xa9, 0xd6, 0xfe, 0xde,
|
|
0xc0, 0x58, 0x50, 0x3a, 0xbc, 0x13, 0x31, 0xcd, 0xd4, 0x55, 0x9f, 0x7f, 0x28, 0x20, 0x1e, 0x98, 0x08, 0x6a, 0x86,
|
|
0xaf, 0x22, 0xfc, 0x19, 0x81, 0xca, 0xe0, 0x57, 0x08, 0x3e, 0x86, 0x90, 0x62, 0xec, 0x29, 0x8d, 0xde, 0xe5, 0x98,
|
|
0x4b, 0x2a, 0xb7, 0x5f, 0x36, 0xb8, 0x16, 0xf2, 0x8e, 0xc5, 0xa4, 0x53, 0x3b, 0x7d, 0xd3, 0x61, 0x9d, 0xe8, 0x69,
|
|
0x8e, 0xae, 0xe4, 0x7c, 0x4b, 0x61, 0xf7, 0x68, 0x46, 0xae, 0xb2, 0xfc, 0x75, 0x81, 0xe7, 0x20, 0x4a, 0x98, 0x37,
|
|
0x2a, 0x96, 0x9f, 0x2e, 0xe8, 0x1c, 0x4e, 0x89, 0xf4, 0x66, 0xc7, 0x6a, 0xd2, 0xaf, 0x1d, 0xbc, 0x09, 0xb1, 0xc6,
|
|
0xf4, 0x52, 0xc7, 0x7d, 0x92, 0xa1, 0xad, 0xb8, 0x7d, 0xb2, 0xa1, 0xb5, 0xb8, 0x77, 0x32, 0xa6, 0x95, 0xba, 0xef,
|
|
0x33, 0x0c, 0x15, 0xc5, 0xcf, 0x13, 0x14, 0x0d, 0xcf, 0x45, 0x94, 0x33, 0x2f, 0x55, 0xdc, 0x3f, 0x19, 0xd0, 0x0a,
|
|
0xdc, 0x07, 0x19, 0xc2, 0x8a, 0xd1, 0xa7, 0x1c, 0x7a, 0x89, 0xe3, 0x26, 0xc9, 0xda, 0xd6, 0xdb, 0x1e, 0xdb, 0x48,
|
|
0x5b, 0x76, 0xbb, 0x66, 0xf3, 0x6a, 0xc5, 0xef, 0x13, 0x0c, 0x0d, 0xc5, 0xc5, 0x93, 0x13, 0x2d, 0xcd, 0xdd, 0x95,
|
|
0x99, 0xaf, 0x2a, 0xfc, 0x1f, 0x01, 0xc8, 0x00, 0x56, 0x80, 0x3e, 0xe0, 0x10, 0x48, 0x0c, 0x36, 0x85, 0xd6, 0xe3,
|
|
0x1e, 0xc9, 0xc8, 0x56, 0xd6, 0xbe, 0xde, 0xf0, 0x58, 0x44, 0x3a, 0xb3, 0x53, 0x35, 0xfd, 0xd7, 0x01, 0x9e, 0x80,
|
|
0x68, 0x60, 0x2e, 0xa8, 0x1c, 0x7e, 0x89, 0xe0, 0x66, 0xc8, 0x2a, 0xd6, 0x9f, 0x1e, 0xe8, 0x08, 0x4e, 0x86, 0xb4,
|
|
0x62, 0xf7, 0x69, 0x86, 0xae, 0xe2, 0xfc, 0x49, 0x81, 0xf6, 0xe0, 0x46, 0xc8, 0x32, 0xd6, 0x95, 0x9e, 0xef, 0x28,
|
|
0x4c, 0x1e, 0xb5, 0xc8, 0x77, 0x16, 0xa6, 0x8e, 0xfa, 0xe4, 0x43, 0x0b, 0x71, 0xc7, 0x64, 0x52, 0xab, 0x7d, 0xbf,
|
|
0x61, 0xb0, 0x28, 0x74, 0x1e, 0xa7, 0x48, 0x7a, 0xb6, 0xa3, 0x36, 0xf9, 0xd6, 0xc2, 0xde, 0xd1, 0x98, 0x5c, 0x6a,
|
|
0xb9, 0xef, 0x32, 0xcc, 0x15, 0x95, 0xcf, 0x2f, 0x14, 0x1c, 0x0f, 0x49, 0xc4, 0x36, 0xd3, 0x56, 0xdd, 0xfe, 0xd9,
|
|
0x80, 0x5a, 0xe0, 0x3b, 0x08, 0x13, 0x46, 0x8d, 0xf2, 0xe5, 0x85, 0x8b, 0x23, 0x27, 0x59, 0xda, 0xba, 0xdb, 0x33,
|
|
0x1b, 0x55, 0xcb, 0x7f, 0x17, 0x60, 0x0e, 0xa8, 0x04, 0x7e, 0x83, 0x60, 0x61, 0xe8, 0x28, 0x4e, 0x9e, 0xb4, 0x68,
|
|
0x77, 0x6e, 0xa6, 0xac, 0x7a, 0xfd, 0xe3, 0x01, 0x89, 0xc0, 0x66, 0xd0, 0x2a, 0xdc, 0x1f, 0x19, 0xc8, 0x0a, 0xd6,
|
|
0x87, 0x1e, 0xe2, 0x88, 0x49, 0xa6, 0xb6, 0xfa, 0xf6, 0xc3, 0x06, 0xd1, 0xc2, 0xdc, 0x51, 0x99, 0xfc, 0x6a, 0xc1,
|
|
0xef, 0x10, 0x4c, 0x0c, 0x35, 0xc5, 0xd7, 0x13, 0x1e, 0x8d, 0xc8, 0x65, 0x96, 0xab, 0x2e, 0xff, 0x5c, 0x40, 0x39,
|
|
0xf0, 0x12, 0xc4, 0x0d, 0x93, 0x45, 0xad, 0xf3, 0x3d, 0x85, 0xd1, 0xa3, 0x1c, 0x79, 0xc9, 0xe2, 0xd6, 0xc9, 0x9e,
|
|
0xd6, 0xe8, 0x5e, 0xce, 0xb8, 0x54, 0x72, 0xbf, 0x65, 0xb0, 0x2b, 0x34, 0x1f, 0x57, 0x48, 0x3e, 0xb6, 0x90, 0x76,
|
|
0xec, 0x26, 0xcd, 0xda, 0xd5, 0x9b, 0x1f, 0x2b, 0x48, 0x1f, 0x76, 0x88, 0x26, 0xe6, 0x9a, 0xca, 0xeb, 0x17, 0x0f,
|
|
0x4e, 0x84, 0x34, 0x63, 0x57, 0x69, 0xfe, 0xae, 0xc0, 0x7c, 0x50, 0x21, 0xfc, 0x18, 0x41, 0xca, 0xb0, 0x57, 0x34,
|
|
0x3e, 0x97, 0x50, 0x6e, 0xbc, 0x2c, 0x71, 0xdd, 0xe4, 0x59, 0x8b, 0x7a, 0xe7, 0x63, 0x0a, 0xa9, 0xc7, 0x3e, 0xd2,
|
|
0x90, 0x5d, 0xac, 0x39, 0xbd, 0xd2, 0xf1, 0x9d, 0x84, 0x69, 0xa3, 0x6e, 0xf9, 0xec, 0x42, 0xcd, 0xf1, 0x95, 0x84,
|
|
0x6f, 0x23, 0x6c, 0x19, 0xed, 0xca, 0xcd, 0x97, 0x15, 0xae, 0x8f, 0x3c, 0x64, 0x11, 0xeb, 0x4c, 0x4f, 0x75, 0xf4,
|
|
0x27, 0x07, 0x5a, 0x82, 0xbb, 0x21, 0xb3, 0x58, 0x75, 0xfa, 0xa7, 0x03, 0x3a, 0x81, 0xd3, 0x20, 0x5d, 0xd8, 0x39,
|
|
0x9a, 0x92, 0xeb, 0x2d, 0x8f, 0x5d, 0xa4, 0x39, 0xbb, 0x52, 0xf3, 0x7d, 0x85, 0xe1, 0xa3, 0x08, 0x79, 0xc6, 0xa2,
|
|
0xd2, 0xf9, 0x9d, 0x82, 0xe9, 0xa1, 0x8e, 0xf8, 0x64, 0x42, 0xab, 0x71, 0xbf, 0x64, 0x70, 0x2b, 0x64, 0x1f, 0x6b,
|
|
0x48, 0x2f, 0x76, 0x9c, 0x26, 0xe9, 0xda, 0xce, 0xdb, 0x14, 0x5b, 0x4f, 0x7b, 0x74, 0x23, 0x67, 0x59, 0xea, 0xba,
|
|
0xcf, 0x33, 0x14, 0x15, 0xcf, 0x4f, 0x14, 0x34, 0x0f, 0x57, 0x44, 0x3e, 0xb3, 0x50, 0x75, 0xfc, 0x27, 0x01, 0xda,
|
|
0x80, 0x5b, 0x20, 0x3b, 0x58, 0x13, 0x7a, 0x8d, 0xe3, 0x25, 0x89, 0xdb, 0x26, 0xdb, 0x5a, 0xdb, 0x7b, 0x1b, 0x63,
|
|
0x4b, 0x69, 0xf7, 0x6e, 0xc6, 0xac, 0x52, 0xfd, 0xfd, 0x81, 0x81, 0xa0, 0x60, 0x78, 0x28, 0x22, 0x9e, 0x99, 0xa8,
|
|
0x6a, 0xfe, 0xaf, 0x00, 0x7c, 0x00, 0x21, 0xc0, 0x18, 0x50, 0x0a, 0xbc, 0x07, 0x31, 0xc2, 0x94, 0x51, 0xaf, 0x7c,
|
|
0x7c, 0x21, 0xe1, 0xd8, 0x48, 0x5a, 0xb6, 0xbb, 0x36, 0xf3, 0x56, 0xc5, 0xfe, 0xd3, 0x00, 0x5d, 0xc0, 0x39, 0x90,
|
|
0x12, 0xec, 0x0d, 0x8d, 0xc5, 0xa5, 0x93, 0x3b, 0x2d, 0xd3, 0x5d, 0x9d, 0xf9, 0xa9, 0x82, 0xfe, 0xe1, 0x80, 0x48,
|
|
0x60, 0x36, 0xa8, 0x16, 0xfe, 0x8e, 0xc0, 0x64, 0x50, 0x2b, 0x7c, 0x1f, 0x61, 0xc8, 0x28, 0x56, 0x9e, 0xbe, 0xe8,
|
|
0x70, 0x4e, 0xa4, 0x34, 0x7b, 0x57, 0x63, 0x7e, 0xa9, 0xe0, 0x7e, 0xc8, 0x20, 0x56, 0x98, 0x3e, 0xea, 0x90, 0x4f,
|
|
0x2c, 0x34, 0x1d, 0xd7, 0x49, 0x9e, 0xb6, 0xe8, 0x76, 0xce, 0xa6, 0xd4, 0x7a, 0xdf, 0x63, 0x18, 0x29, 0xca, 0x9e,
|
|
0xd7, 0x28, 0x5e, 0x9e, 0xb8, 0x68, 0x72, 0xae, 0xa5, 0xbc, 0x7b, 0x31, 0xe3, 0x54, 0x49, 0xff, 0x76, 0xc0, 0x26,
|
|
0xd0, 0x1a, 0xdc, 0x0b, 0x19, 0xc7, 0x4a, 0xd2, 0xb7, 0x1d, 0xb6, 0x89, 0xb6, 0xe6, 0xf6, 0xca, 0xc6, 0xd7, 0x12,
|
|
0xde, 0x8d, 0x98, 0x65, 0xaa, 0xab, 0x3f, 0x3f, 0x50, 0x10, 0x3c, 0x0c, 0x11, 0xc5, 0xcc, 0x53, 0x15, 0xfd, 0xcf,
|
|
0x01, 0x94, 0x00, 0x6f, 0x40, 0x2c, 0x30, 0x1d, 0xd4, 0x09, 0x9f, 0x46, 0xe8, 0x32, 0xce, 0x95, 0x94, 0x6f, 0x2f,
|
|
0x6c, 0x1c, 0x2d, 0xc9, 0xdd, 0x96, 0xd9, 0xae, 0xda, 0xfc, 0x5b, 0x01, 0xfb, 0x40, 0x43, 0x70, 0x31, 0xe4, 0x14,
|
|
0x4b, 0x4f, 0x77, 0x74, 0x26, 0xa7, 0x5a, 0xfa, 0xbb, 0x03, 0x33, 0x41, 0xd5, 0xf0, 0x5f, 0x04, 0x38, 0x03, 0x52,
|
|
0x81, 0xfd, 0xa0, 0x41, 0xb8, 0x30, 0x72, 0x94, 0x25, 0xaf, 0x5b, 0x3c, 0x3b, 0x51, 0xd3, 0x7c, 0x5d, 0xe1, 0xf9,
|
|
0x88, 0x42, 0xe6, 0xb1, 0x8a, 0xf4, 0x67, 0x07, 0x6a, 0x82, 0xaf, 0x21, 0xbc, 0x18, 0x71, 0xca, 0xa4, 0x57, 0x3b,
|
|
0x7e, 0x93, 0x60, 0x6d, 0xe8, 0x2d, 0x8e, 0x9d, 0xa4, 0x69, 0xbb, 0x6e, 0xf3, 0x6c, 0x45, 0xed, 0xf3, 0x0d, 0x85,
|
|
0xc5, 0xa3, 0x13, 0x39, 0xcd, 0xd2, 0xd5, 0x9d, 0x9f, 0x29, 0xa8, 0x1e, 0xfe, 0x88, 0x40, 0x66, 0xb0, 0x2a, 0xf4,
|
|
0x1f, 0x07, 0x48, 0x02, 0xb6, 0x81, 0xb6, 0xe0, 0x76, 0xc8, 0x26, 0xd6, 0x9a, 0xde, 0xeb, 0x18, 0x4f, 0x4a, 0xb4,
|
|
0x37, 0x37, 0x56, 0x96, 0xbe, 0xee, 0xf0, 0x4c, 0x44, 0x35, 0xf3, 0x57, 0x05, 0xfe, 0x83, 0x00, 0x61, 0xc0, 0x28,
|
|
0x50, 0x1e, 0xbc, 0x08, 0x71, 0xc6, 0xa4, 0x52, 0xfb, 0x7d, 0x83, 0x61, 0xa1, 0xe8, 0x78, 0x4e, 0xa2, 0xb4, 0x79,
|
|
0xb7, 0x62, 0xf6, 0xa9, 0x86, 0xfe, 0xe2, 0xc0, 0x49, 0x90, 0x36, 0xec, 0x16, 0xcd, 0xce, 0xd5, 0x94, 0x5f, 0x2f,
|
|
0x78, 0x1c, 0x22, 0x89, 0xd9, 0xa6, 0xda, 0xfa, 0xdb, 0x03, 0x1b, 0x41, 0xcb, 0x70, 0x57, 0x64, 0x3e, 0xab, 0x50,
|
|
0x7f, 0x7c, 0x20, 0x21, 0xd8, 0x18, 0x5a, 0x8a, 0xbb, 0x27, 0x33, 0x5a, 0x95, 0xfb, 0x2f, 0x03, 0x5c, 0x01, 0xf9,
|
|
0xc0, 0x42, 0xd0, 0x31, 0x9c, 0x14, 0x69, 0xcf, 0x6e, 0xd4, 0x2c, 0x5f, 0x5d, 0xf8, 0x39, 0x82, 0x92, 0xe1, 0xad,
|
|
0x88, 0x7d, 0xa6, 0xa1, 0xba, 0xf8, 0x73, 0x02, 0xa5, 0xc1, 0xbb, 0x10, 0x73, 0x4c, 0x25, 0xf5, 0xdb, 0x07, 0x1b,
|
|
0x42, 0x8b, 0x71, 0xa7, 0x64, 0x7a, 0xab, 0x63, 0x3f, 0x69, 0xd0, 0x2e, 0xdc, 0x1c, 0x59, 0xc9, 0xfa, 0xd6, 0xc3,
|
|
0x1e, 0xd1, 0xc8, 0x5c, 0x56, 0xb9, 0xfe, 0xf2, 0xc0, 0x45, 0x90, 0x33, 0x2c, 0x15, 0xdd, 0xcf, 0x19, 0x94, 0x0a,
|
|
0xef, 0x47, 0x0c, 0x32, 0x85, 0xd5, 0xa3, 0x1f, 0x39, 0xc8, 0x12, 0xd6, 0x8d, 0x9e, 0xe5, 0xa8, 0x4b, 0x3e, 0xb7,
|
|
0x50, 0x76, 0xbc, 0x26, 0xf1, 0xda, 0xc4, 0x5b, 0x13, 0x7b, 0x4d, 0xe3, 0x75, 0x89, 0xe7, 0x26, 0xca, 0x9a, 0xd7,
|
|
0x2b, 0x1e, 0x9f, 0x48, 0x68, 0x36, 0xae, 0x96, 0xfc, 0x6e, 0xc1, 0xec, 0x50, 0x4d, 0xfc, 0x35, 0x81, 0xd7, 0x20,
|
|
0x5e, 0x98, 0x38, 0x6a, 0x92, 0xaf, 0x2d, 0xbc, 0x1d, 0xb1, 0xc9, 0xb4, 0x56, 0xf7, 0x7e, 0xc6, 0xa0, 0x52, 0xf8,
|
|
0x3d, 0x82, 0x91, 0xa1, 0xac, 0x78, 0x7d, 0xe2, 0xa1, 0x89, 0xb8, 0x66, 0xf2, 0xaa, 0xc5, 0xbf, 0x13, 0x30, 0x0d,
|
|
0xd4, 0x05, 0x9f, 0x43, 0x28, 0x31, 0xde, 0x94, 0x58, 0x6f, 0x7a, 0xac, 0x23, 0x3d, 0xd9, 0xd1, 0x9a, 0xdc, 0x6b,
|
|
0x19, 0xef, 0x4a, 0xcc, 0x37, 0x15, 0xd6, 0x8f, 0x1e, 0xe4, 0x08, 0x4b, 0x46, 0xb7, 0x72, 0xf6, 0xa5, 0x86, 0xfb,
|
|
0x22, 0xc3, 0x59, 0x91, 0xfa, 0xec, 0x43, 0x0d, 0xf1, 0xc5, 0x84, 0x53, 0x23, 0x7d, 0xd9, 0xe1, 0x9a, 0xc8, 0x6b,
|
|
0x16, 0xaf, 0x4e, 0xfc, 0x34, 0x41, 0xd7, 0x70, 0x5e, 0xa4, 0x38, 0x7b, 0x52, 0xa3, 0x7d, 0xb9, 0xe1, 0xb2, 0xc8,
|
|
0x75, 0x96, 0xa7, 0x2e, 0xfa, 0x9c, 0x43, 0x29, 0xf1, 0xde, 0xc4, 0x58, 0x53, 0x7a, 0xbd, 0xe3, 0x31, 0x89, 0xd4,
|
|
0x66, 0xdf, 0x6a, 0xd8, 0x2f, 0x1a, 0x9c, 0x0b, 0x29, 0xc7, 0x5e, 0xd2, 0xb8, 0x5d, 0xb2, 0xb9, 0xb5, 0xb2, 0xf7,
|
|
0x35, 0x86, 0x97, 0x22, 0xee, 0x99, 0x8c, 0x6a, 0xe5, 0xef, 0x0b, 0x0c, 0x07, 0x45, 0xc2, 0xb3, 0x11, 0xb5, 0xcc,
|
|
0x77, 0x15, 0xe6, 0x8f, 0x0a, 0xe4, 0x07, 0x0b, 0x42, 0x87, 0x71, 0xa2, 0xa4, 0x79, 0xbb, 0x62, 0xf3, 0x69, 0x85,
|
|
0xee, 0xe3, 0x0c, 0x49, 0xc5, 0xf6, 0xd3, 0x06, 0xdd, 0xc2, 0xd9, 0x91, 0x9a, 0xec, 0x6b, 0x0d, 0xef, 0x45, 0x8c,
|
|
0x33, 0x25, 0xd5, 0xdb, 0x1f, 0x1b, 0x48, 0x0b, 0x76, 0x87, 0x66, 0xe2, 0xaa, 0xc9, 0xbf, 0x16, 0xf0, 0x0e, 0xc4,
|
|
0x04, 0x53, 0x43, 0x7d, 0xf1, 0xe1, 0x84, 0x48, 0x63, 0x76, 0xa9, 0xe6, 0xfe, 0xca, 0xc0, 0x57, 0x10, 0x3e, 0x8c,
|
|
0x10, 0x65, 0xcc, 0x2b, 0x15, 0xdf, 0x4f, 0x18, 0x34, 0x0a, 0x97, 0x47, 0x2e, 0xb2, 0x9c, 0x75, 0xa9, 0xe7, 0x3e,
|
|
0xca, 0x90, 0x57, 0x2c, 0x3e, 0x9d, 0xd0, 0x69, 0x9c, 0x2e, 0xe9, 0xdc, 0x4e, 0xd9, 0xf4, 0x5a, 0xc7, 0x7b, 0x12,
|
|
0xa3, 0x4d, 0xb9, 0xf5, 0xb2, 0xc7, 0x35, 0x92, 0x97, 0x2d, 0xae, 0x9d, 0xbc, 0x69, 0xb1, 0xee, 0xf4, 0x4c, 0x47,
|
|
0x75, 0xf2, 0xa7, 0x05, 0xba, 0x83, 0x33, 0x21, 0xd5, 0xd8, 0x5f, 0x1a, 0xb8, 0x0b, 0x32, 0x87, 0x55, 0xa2, 0xbf,
|
|
0x39, 0xb0, 0x12, 0xf4, 0x0d, 0x87, 0x45, 0xa2, 0xb3, 0x39, 0xb5, 0xd2, 0xf7, 0x1d, 0x86, 0x89, 0xa2, 0xe6, 0xf9,
|
|
0x8a, 0xc2, 0xe7, 0x11, 0x8a, 0x8c, 0x67, 0x25, 0xea, 0x9b, 0x0f, 0x2b, 0x44, 0x1f, 0x73, 0x48, 0x25, 0xf6, 0x9b,
|
|
0x06, 0xeb, 0x42, 0xcf, 0x71, 0x94, 0x24, 0x6f, 0x5b, 0x6c, 0x3b, 0x6d, 0xd3, 0x6d, 0x9d, 0xed, 0xa9, 0x8d, 0xbe,
|
|
0xe5, 0xb0, 0x4b, 0x34, 0x37, 0x57, 0x56, 0xbe, 0xbe, 0xf0, 0x70, 0x44, 0x24, 0x33, 0x5b, 0x55, 0xfb, 0x7f, 0x03,
|
|
0x60, 0x01, 0xe8, 0x00, 0x4e, 0x80, 0x34, 0x60, 0x17, 0x68, 0x0e, 0xae, 0x84, 0x7c, 0x63, 0x61, 0xe9, 0xe8, 0x4e,
|
|
0xce, 0xb4, 0x54, 0x77, 0x7f, 0x66, 0xa0, 0x2a, 0xf8, 0x1f, 0x02, 0x88, 0x01, 0xa6, 0x80, 0x7a, 0xe0, 0x23, 0x08,
|
|
0x19, 0xc6, 0x8a, 0xd2, 0xe7, 0x1d, 0x8a, 0x89, 0xa7, 0x26, 0xfa, 0x9a, 0xc3, 0x2b, 0x11, 0xdf, 0x4c, 0x58, 0x35,
|
|
0xfa, 0x97, 0x03, 0x2e, 0x81, 0xdc, 0x60, 0x59, 0xe8, 0x3a, 0xce, 0x93, 0x14, 0x6d, 0xcf, 0x6d, 0x94, 0x2d, 0xaf,
|
|
0x5d, 0xbc, 0x39, 0xb1, 0xd2, 0xf4, 0x5d, 0x87, 0x79, 0xa2, 0xa2, 0xf9, 0xb9, 0x82, 0xf2, 0xe1, 0x85, 0x88, 0x63,
|
|
0x26, 0xa9, 0xda, 0xfe, 0xdb, 0x00, 0x5b, 0x40, 0x3b, 0x70, 0x13, 0x64, 0x0d, 0xeb, 0x45, 0x8f, 0x73, 0x24, 0x25,
|
|
0xdb, 0x5b, 0x1b, 0x7b, 0x4b, 0x63, 0x77, 0x69, 0xe6, 0xae, 0xca, 0xfc, 0x57, 0x01, 0xfe, 0x80, 0x40, 0x60, 0x30,
|
|
0x28, 0x14, 0x1e, 0x8f, 0x48, 0x64, 0x36, 0xab, 0x56, 0xff, 0x7e, 0xc0, 0x20, 0x50, 0x18, 0x3c, 0x0a, 0x91, 0xc7,
|
|
0x2c, 0x52, 0x9d, 0xfd, 0xa9, 0x81, 0xbe, 0xe0, 0x70, 0x48, 0x24, 0x36, 0x9b, 0x56, 0xeb, 0x7e, 0xcf, 0x60, 0x54,
|
|
0x28, 0x3f, 0x5e, 0x90, 0x38, 0x6c, 0x12, 0xad, 0xcd, 0xbd, 0x95, 0xb1, 0xaf, 0x34, 0x7c, 0x17, 0x61, 0xce, 0xa8,
|
|
0x54, 0x7e, 0xbf, 0x60, 0x70, 0x28, 0x24, 0x1e, 0x9b, 0x48, 0x6b, 0x76, 0xaf, 0x66, 0xfc, 0x2a, 0xc1, 0xdf, 0x10,
|
|
0x58, 0x0c, 0x3a, 0x85, 0xd3, 0x23, 0x1d, 0xd9, 0xc9, 0x9a, 0xd6, 0xeb, 0x1e, 0xcf, 0x48, 0x54, 0x36, 0xbf, 0x56,
|
|
0xf0, 0x3e, 0xc4, 0x10, 0x53, 0x4c, 0x3d, 0xf5, 0xd1, 0x87, 0x1c, 0x62, 0x89, 0xe9, 0xa6, 0xce, 0xfa, 0xd4, 0x43,
|
|
0x1f, 0x71, 0xc8, 0x24, 0x56, 0x9b, 0x7e, 0xeb, 0x60, 0x4f, 0x68, 0x34, 0x2e, 0x97, 0x5c, 0x6e, 0xb9, 0xec, 0x72,
|
|
0xcd, 0xe5, 0x95, 0x8b, 0x2f, 0x27, 0x5c, 0x1a, 0xb9, 0xcb, 0x32, 0xd7, 0x55, 0x9e, 0xbf, 0x28, 0x70, 0x1e, 0xa4,
|
|
0x08, 0x7b, 0x46, 0xa3, 0x72, 0xf9, 0xe5, 0x82, 0xcb, 0x21, 0x97, 0x58, 0x6e, 0xba, 0xac, 0x73, 0x3d, 0xe5, 0xd1,
|
|
0x8b, 0x1c, 0x67, 0x49, 0xea, 0xb6, 0xcf, 0x36, 0xd4, 0x16, 0xdf, 0x4e, 0xd8, 0x34, 0x5a, 0x97, 0x7b, 0x2e, 0xa3,
|
|
0x5c, 0x79, 0xf9, 0xe2, 0xc2, 0xc9, 0x91, 0x96, 0xec, 0x6e, 0xcd, 0xec, 0x55, 0x8d, 0xff, 0x25, 0x80, 0x1b, 0x20,
|
|
0x0b, 0x58, 0x07, 0x7a, 0x82, 0xa3, 0x21, 0xb9, 0xd8, 0x72, 0xda, 0xa5, 0x9b, 0x3b, 0x2b, 0x53, 0x5f, 0x7d, 0xf8,
|
|
0x21, 0x82, 0x98, 0x61, 0xaa, 0xa8, 0x7f, 0x3e, 0xa0, 0x10, 0x78, 0x0c, 0x22, 0x85, 0xd9, 0xa3, 0x1a, 0xf9, 0xcb,
|
|
0x02, 0xd7, 0x41, 0x9e, 0xb0, 0x68, 0x74, 0x2e, 0xa7, 0x5c, 0x7a, 0xb9, 0xe3, 0x32, 0xc9, 0xd5, 0x96, 0xdf, 0x2e,
|
|
0xd8, 0x1c, 0x5a, 0x89, 0xfb, 0x26, 0xc3, 0x5a, 0xd1, 0xfb, 0x1c, 0x43, 0x49, 0xf1, 0xf6, 0xc4, 0x46, 0xd3, 0x72,
|
|
0xdd, 0xe5, 0x99};
|
|
|
|
void descramble_sector(uint8_t *buffer) {
|
|
#define CD_SECTOR_LEN 2352
|
|
|
|
for (uint32_t i = 12; i < CD_SECTOR_LEN; i++) {
|
|
buffer[i] ^= s_sector_scramble[i - 12];
|
|
}
|
|
}
|
|
|
|
static inline uint32_t unBCD(uint32_t val) {
|
|
return ((val & 0xf0) >> 4) * 10 + (val & 0x0f);
|
|
}
|
|
|
|
void check_scramble(int lba, uint8_t *buffer) {
|
|
// Check for sync pattern to confirm mode 2
|
|
// Starts and ends with 0x00 and ...
|
|
if ((buffer[0] != 0) || (buffer[11] != 0))
|
|
return;
|
|
|
|
// ... inbetween there are 0xff bytes
|
|
for (uint32_t i = 01; i < 11; i++)
|
|
if (buffer[i] != 0xff)
|
|
return;
|
|
|
|
// Sync pattern confirmed. check validity of mode2 header
|
|
uint32_t mm, ss, ff;
|
|
uint8_t mode;
|
|
|
|
mm = unBCD(buffer[12]);
|
|
ss = unBCD(buffer[13]);
|
|
ff = unBCD(buffer[14]);
|
|
mode = buffer[15];
|
|
int mode2_lba = mm * 75 * 60 + ss * 75 + ff;
|
|
|
|
if (mode2_lba == lba && mode == 2) {
|
|
// Is a valid header. Do nothing
|
|
} else {
|
|
// Can we fix it? Let's test on 4 bytes
|
|
mm = unBCD(buffer[12] ^ s_sector_scramble[0]);
|
|
ss = unBCD(buffer[13] ^ s_sector_scramble[1]);
|
|
ff = unBCD(buffer[14] ^ s_sector_scramble[2]);
|
|
mode = buffer[15] ^ s_sector_scramble[3];
|
|
mode2_lba = mm * 75 * 60 + ss * 75 + ff;
|
|
if (mode2_lba == lba && mode == 2) {
|
|
descramble_sector(buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
void subcode_data(int lba, struct subcode &out) {
|
|
int fake_lba = lba;
|
|
if (fake_lba < 150)
|
|
fake_lba += 150;
|
|
uint8_t m, s, f;
|
|
m = fake_lba / (60 * 75);
|
|
fake_lba -= m * (60 * 75);
|
|
s = fake_lba / 75;
|
|
f = fake_lba % 75;
|
|
|
|
int toc_entry_index = lba + 0x10000;
|
|
if (lba < 0 && toc_entry_index < toc_entry_count) {
|
|
|
|
auto &toc_entry = toc_buffer[toc_entry_index];
|
|
|
|
out.control = htons(toc_entry.control);
|
|
out.track = 0; // Track 0 for TOC
|
|
out.index = htons(toc_entry.track);
|
|
out.mode1_mins = htons(BCD(m));
|
|
out.mode1_secs = htons(BCD(s));
|
|
out.mode1_frac = htons(BCD(f));
|
|
out.mode1_zero = 0;
|
|
out.mode1_amins = htons(toc_entry.m);
|
|
out.mode1_asecs = htons(toc_entry.s);
|
|
out.mode1_afrac = htons(toc_entry.f);
|
|
out.mode1_crc0 = htons(0xff);
|
|
out.mode1_crc1 = htons(0xff);
|
|
|
|
// printf("toc lba=%d %02x %02x %02x %02x %02x\n", toc_entry_index, out.control, out.index, out.mode1_amins,
|
|
// out.mode1_asecs, out.mode1_afrac);
|
|
} else {
|
|
int track = 1;
|
|
out.control = htons(0x01);
|
|
out.track = htons(1); // Track 1 for TOC
|
|
out.index = htons(1);
|
|
out.mode1_mins = htons(BCD(m));
|
|
out.mode1_secs = htons(BCD(s));
|
|
out.mode1_frac = htons(BCD(f));
|
|
out.mode1_zero = 0;
|
|
out.mode1_amins = htons(BCD(m));
|
|
out.mode1_asecs = htons(BCD(s));
|
|
out.mode1_afrac = htons(BCD(f));
|
|
out.mode1_crc0 = htons(0xff);
|
|
out.mode1_crc1 = htons(0xff);
|
|
|
|
// printf("data lba=%d %02x %02x %02x %02x %02x\n", lba, out.control, out.track, BCD(m), BCD(s), BCD(f));
|
|
}
|
|
|
|
uint16_t crc_accum = 0;
|
|
uint8_t *crc = reinterpret_cast<uint8_t *>(&out);
|
|
for (int i = 0; i < 12; i++)
|
|
crc_accum = CRC_CCITT_ROUND(crc_accum, crc[1 + i * 2]);
|
|
|
|
out.mode1_crc0 = htons((crc_accum >> 8) & 0xff);
|
|
out.mode1_crc1 = htons(crc_accum & 0xff);
|
|
|
|
printf("subcode %d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", lba, ntohs(out.control),
|
|
ntohs(out.track), ntohs(out.index), ntohs(out.mode1_mins), ntohs(out.mode1_secs), ntohs(out.mode1_frac),
|
|
ntohs(out.mode1_zero), ntohs(out.mode1_amins), ntohs(out.mode1_asecs), ntohs(out.mode1_afrac),
|
|
ntohs(out.mode1_crc0), ntohs(out.mode1_crc1));
|
|
}
|
|
|
|
class CDi {
|
|
public:
|
|
#ifdef SIMULATE_RC5
|
|
FILE *rc5_file;
|
|
uint64_t rc5_fliptime{0};
|
|
uint32_t rc5_nextstate{1};
|
|
#endif
|
|
|
|
Vemu dut;
|
|
uint64_t step = 0;
|
|
uint64_t sim_time = 0;
|
|
int frame_index = 0;
|
|
int release_button_frame{-1};
|
|
int fmv_frame_cnt{0};
|
|
|
|
private:
|
|
FILE *f_audio_left{nullptr};
|
|
FILE *f_audio_right{nullptr};
|
|
FILE *f_fma{nullptr};
|
|
FILE *f_fma_mp2{nullptr};
|
|
FILE *f_fmv{nullptr};
|
|
FILE *f_fmv_m1v{nullptr};
|
|
FILE *f_uart{nullptr};
|
|
|
|
uint8_t output_image[size] = {0};
|
|
uint32_t regfile[16];
|
|
#ifdef TRACE
|
|
tracetype_t m_trace;
|
|
#endif
|
|
|
|
uint32_t print_instructions = 0;
|
|
uint32_t prevpc = 0;
|
|
uint32_t leave_sys_callpc = 0;
|
|
|
|
int pixel_index = 0;
|
|
|
|
uint16_t hps_buffer[4096];
|
|
uint16_t hps_buffer_index = 0;
|
|
bool hps_nvram_backup_active{false};
|
|
bool ignore_first_hps_din{false};
|
|
|
|
int instanceid;
|
|
|
|
std::chrono::_V2::system_clock::time_point start;
|
|
int sd_rd_q;
|
|
static constexpr uint32_t kSectorHeaderSize{12};
|
|
static constexpr uint32_t kSectorSize{2352};
|
|
static constexpr uint32_t kWordsPerSubcodeFrame{12};
|
|
static constexpr uint32_t kWordsPerSector{kWordsPerSubcodeFrame + kSectorSize / 2};
|
|
|
|
uint32_t get_pixel_value(uint32_t x, uint32_t y) {
|
|
uint8_t *pixel = &output_image[(width * y + x) * 3];
|
|
uint32_t r = static_cast<uint32_t>(*pixel++) << 16;
|
|
uint32_t g = static_cast<uint32_t>(*pixel++) << 8;
|
|
uint32_t b = static_cast<uint32_t>(*pixel++);
|
|
return r | g | b;
|
|
}
|
|
|
|
void write_png_file(const char *filename) {
|
|
FILE *fp = fopen(filename, "wb");
|
|
if (!fp)
|
|
abort();
|
|
|
|
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
if (!png)
|
|
abort();
|
|
|
|
png_infop info = png_create_info_struct(png);
|
|
if (!info)
|
|
abort();
|
|
|
|
if (setjmp(png_jmpbuf(png)))
|
|
abort();
|
|
|
|
png_init_io(png, fp);
|
|
|
|
int png_height_scale = 4;
|
|
int png_height = height * png_height_scale;
|
|
// Output is 8bit depth, RGBA format.
|
|
png_set_IHDR(png, info, width, png_height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
|
png_write_info(png, info);
|
|
|
|
png_bytepp row_pointers = (png_bytepp)png_malloc(png, sizeof(png_bytepp) * png_height);
|
|
|
|
for (int i = 0; i < png_height; i++) {
|
|
row_pointers[i] = &output_image[width * 3 * (i / png_height_scale)];
|
|
}
|
|
|
|
png_write_image(png, row_pointers);
|
|
png_write_end(png, NULL);
|
|
|
|
free(row_pointers);
|
|
|
|
fclose(fp);
|
|
|
|
png_destroy_write_struct(&png, &info);
|
|
}
|
|
|
|
uint16_t phase_accumulator;
|
|
|
|
void clock() {
|
|
for (int i = 0; i < 4; i++) {
|
|
// clk_sys is 30 MHz
|
|
dut.rootp->emu__DOT__clk_sys = (sim_time & 2);
|
|
|
|
// clk_mpeg is 60 MHz
|
|
dut.rootp->emu__DOT__clk_mpeg = (sim_time & 1);
|
|
|
|
// clk_audio is 22.2264 MHz
|
|
phase_accumulator += 24277 / 2;
|
|
dut.rootp->emu__DOT__clk_audio = (phase_accumulator & 0x8000) ? 1 : 0;
|
|
|
|
dut.eval();
|
|
#ifdef TRACE
|
|
if (do_trace) {
|
|
// emu__DOT__clk_sys is 30 MHz
|
|
// One period is 33333.3333 ps
|
|
// sim_time counts the half periods
|
|
m_trace.dump(sim_time * 33333 / 2);
|
|
}
|
|
#endif
|
|
sim_time++;
|
|
}
|
|
}
|
|
|
|
public:
|
|
void loadfile(uint16_t index, const char *path) {
|
|
|
|
FILE *f = fopen(path, "rb");
|
|
assert(f);
|
|
|
|
uint16_t transferword;
|
|
|
|
dut.rootp->emu__DOT__ioctl_addr = 0;
|
|
dut.rootp->emu__DOT__ioctl_index = index;
|
|
|
|
// make some clocks before starting
|
|
for (int step = 0; step < 300; step++) {
|
|
clock();
|
|
}
|
|
|
|
while (fread(&transferword, 2, 1, f) == 1) {
|
|
dut.rootp->emu__DOT__ioctl_wr = 1;
|
|
dut.rootp->emu__DOT__ioctl_dout = transferword;
|
|
|
|
clock();
|
|
dut.rootp->emu__DOT__ioctl_wr = 0;
|
|
|
|
// make some clocks to avoid asking for busy
|
|
// the real MiSTer has 31 clocks between writes
|
|
// we are going for ~20 to put more stress on it.
|
|
for (int i = 0; i < 20; i++) {
|
|
clock();
|
|
}
|
|
dut.rootp->emu__DOT__ioctl_addr += 2;
|
|
clock();
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
void printstate() {
|
|
#ifdef SCC68070
|
|
uint32_t pc = dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__exe_pc;
|
|
// d0 = dut.rootp->fx68k_tb__DOT__d0;
|
|
memcpy(regfile, &dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__regfile[0],
|
|
sizeof(regfile));
|
|
|
|
printf("%08x ", pc);
|
|
for (int i = 0; i < 16; i++) {
|
|
if (i == 8)
|
|
printf(" ");
|
|
printf(" %08x", regfile[i]);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
|
|
void modelstep() {
|
|
step++;
|
|
clock();
|
|
|
|
#ifdef SIMULATE_RC5
|
|
if (sim_time >= rc5_fliptime) {
|
|
dut.rootp->emu__DOT__rc_eye = rc5_nextstate;
|
|
|
|
fprintf(stderr, "Set RC5!\n");
|
|
char buffer[100];
|
|
if (!fgets(buffer, sizeof(buffer), rc5_file))
|
|
exit(1);
|
|
char *endptr;
|
|
// primitive csv parsing
|
|
float next_flip = std::max(strtof(buffer, &endptr) - 2.58810f + 3.0f, 0.0f) * 30e6 * 2;
|
|
rc5_nextstate = strtol(endptr + 1, &endptr, 10);
|
|
assert(rc5_nextstate <= 1);
|
|
printf("%f %d\n", next_flip, rc5_nextstate);
|
|
rc5_fliptime = next_flip;
|
|
}
|
|
#endif
|
|
|
|
if ((step % 100000) == 0) {
|
|
printf("%d\n", step);
|
|
}
|
|
|
|
dut.rootp->emu__DOT__cd_media_change = (step == 1300000);
|
|
if (step == 1300000)
|
|
printf("Media change!\n");
|
|
|
|
#ifdef SCC68070
|
|
// Abort on illegal Instructions
|
|
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__trap_illegal) {
|
|
fprintf(stderr, "Illegal Instruction!\n");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
dut.rootp->emu__DOT__nvram_media_change = (step == 2000);
|
|
// Simulate CD data delivery from HPS
|
|
if (dut.rootp->emu__DOT__cd_hps_req && sd_rd_q == 0 && dut.rootp->emu__DOT__nvram_hps_ack == 0) {
|
|
assert(dut.rootp->emu__DOT__cd_hps_ack == 0);
|
|
dut.rootp->emu__DOT__cd_hps_ack = 1;
|
|
|
|
uint32_t lba = dut.rootp->emu__DOT__cd_hps_lba;
|
|
uint32_t m_time = dut.rootp->emu__DOT__cditop__DOT__cdic_inst__DOT__time_register;
|
|
|
|
uint32_t reference_lba = lba_from_time(m_time);
|
|
// assert(lba == reference_lba);
|
|
// assert(lba >= 150);
|
|
|
|
if (lba < 150)
|
|
lba += 150;
|
|
uint32_t file_offset = (lba - 150) * kSectorSize;
|
|
|
|
printf("Request CD Sector %x %x %x\n", m_time, lba, file_offset);
|
|
|
|
int res = fseek(f_cd_bin, file_offset, SEEK_SET);
|
|
assert(res == 0);
|
|
|
|
fread(hps_buffer, 1, kSectorSize, f_cd_bin);
|
|
|
|
check_scramble(lba, reinterpret_cast<uint8_t *>(hps_buffer));
|
|
struct subcode &out = *reinterpret_cast<struct subcode *>(&hps_buffer[kSectorSize / 2]);
|
|
subcode_data(dut.rootp->emu__DOT__cd_hps_lba, out);
|
|
hps_buffer_index = 0;
|
|
}
|
|
|
|
if (dut.rootp->emu__DOT__nvram_hps_rd && sd_rd_q == 0 && dut.rootp->emu__DOT__cd_hps_ack == 0) {
|
|
assert(dut.rootp->emu__DOT__nvram_hps_ack == 0);
|
|
dut.rootp->emu__DOT__nvram_hps_ack = 1;
|
|
|
|
printf("Request NvRAM restore!\n");
|
|
|
|
FILE *f_nvram_bin = fopen("save_in.bin", "rb");
|
|
if (f_nvram_bin) {
|
|
fread(hps_buffer, 1, 8192, f_nvram_bin);
|
|
hps_buffer_index = 0;
|
|
dut.rootp->emu__DOT__sd_buff_addr = hps_buffer_index;
|
|
fclose(f_nvram_bin);
|
|
}
|
|
}
|
|
|
|
if (dut.rootp->emu__DOT__nvram_hps_wr && sd_rd_q == 0 && dut.rootp->emu__DOT__cd_hps_ack == 0) {
|
|
assert(dut.rootp->emu__DOT__nvram_hps_ack == 0);
|
|
dut.rootp->emu__DOT__nvram_hps_ack = 1;
|
|
|
|
printf("Request NvRAM backup!\n");
|
|
hps_buffer_index = 0;
|
|
hps_nvram_backup_active = true;
|
|
dut.rootp->emu__DOT__sd_buff_addr = hps_buffer_index;
|
|
ignore_first_hps_din = true;
|
|
}
|
|
|
|
dut.rootp->emu__DOT__sd_buff_wr = 0;
|
|
if (dut.rootp->emu__DOT__cd_hps_ack && (step % 200) == 15) {
|
|
if (hps_buffer_index == kWordsPerSector) {
|
|
dut.rootp->emu__DOT__cd_hps_ack = 0;
|
|
printf("Sector transferred!\n");
|
|
} else {
|
|
dut.rootp->emu__DOT__sd_buff_dout = hps_buffer[hps_buffer_index];
|
|
dut.rootp->emu__DOT__sd_buff_wr = 1;
|
|
hps_buffer_index++;
|
|
}
|
|
}
|
|
|
|
if (dut.rootp->emu__DOT__nvram_hps_ack && (step % 20) == 15) {
|
|
if (hps_nvram_backup_active) {
|
|
if (hps_buffer_index == 4096) {
|
|
dut.rootp->emu__DOT__nvram_hps_ack = 0;
|
|
printf("NvRAM backed up!\n");
|
|
|
|
FILE *f_nvram_bin = fopen("save_out.bin", "wb");
|
|
assert(f_nvram_bin);
|
|
fwrite(hps_buffer, 1, 8192, f_nvram_bin);
|
|
hps_nvram_backup_active = false;
|
|
fclose(f_nvram_bin);
|
|
} else {
|
|
hps_buffer[hps_buffer_index] = dut.rootp->emu__DOT__nvram_hps_din;
|
|
|
|
if (ignore_first_hps_din)
|
|
ignore_first_hps_din = false;
|
|
else
|
|
hps_buffer_index++;
|
|
|
|
dut.rootp->emu__DOT__sd_buff_addr = hps_buffer_index;
|
|
}
|
|
|
|
} else {
|
|
if (hps_buffer_index == 4096) {
|
|
dut.rootp->emu__DOT__nvram_hps_ack = 0;
|
|
printf("NvRAM restored!\n");
|
|
} else {
|
|
dut.rootp->emu__DOT__sd_buff_dout = hps_buffer[hps_buffer_index];
|
|
dut.rootp->emu__DOT__sd_buff_wr = 1;
|
|
dut.rootp->emu__DOT__sd_buff_addr = hps_buffer_index;
|
|
|
|
hps_buffer_index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
sd_rd_q =
|
|
dut.rootp->emu__DOT__cd_hps_req || dut.rootp->emu__DOT__nvram_hps_rd || dut.rootp->emu__DOT__nvram_hps_wr;
|
|
|
|
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__uart_tx_data_valid) {
|
|
fputc(dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__uart_transmit_holding_register, f_uart);
|
|
fflush(f_uart);
|
|
}
|
|
|
|
// Trace System Calls
|
|
#ifdef SCC68070
|
|
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__decodeopc &&
|
|
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__clkena_in) {
|
|
|
|
uint32_t m_pc = dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__exe_pc;
|
|
|
|
if (m_pc == 0x62c) {
|
|
assert((prevpc & 1) == 0);
|
|
uint32_t callpos = ((prevpc & 0x3fffff) >> 1) + 1;
|
|
uint32_t call = dut.rootp->emu__DOT__rom[callpos];
|
|
printf("Syscall %x %x %s\n", prevpc, call, systemCallNameToString(static_cast<SystemCallType>(call)));
|
|
leave_sys_callpc = prevpc + 4;
|
|
|
|
// SysDbg ? Just give up!
|
|
if (static_cast<SystemCallType>(call) == F_SysDbg) {
|
|
fprintf(stderr, "System halted and debugger calted!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (m_pc == leave_sys_callpc) {
|
|
printf("Return from Syscall %x %x\n",
|
|
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__flags,
|
|
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__flagssr);
|
|
printstate();
|
|
}
|
|
|
|
prevpc = m_pc;
|
|
}
|
|
|
|
// Trace CPU state
|
|
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__decodeopc &&
|
|
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__clkena_in) {
|
|
}
|
|
#endif
|
|
|
|
// Simulate television
|
|
if (dut.rootp->emu__DOT__cditop__DOT__mcd212_inst__DOT__video_y == 0 &&
|
|
dut.rootp->emu__DOT__cditop__DOT__mcd212_inst__DOT__video_x == 0) {
|
|
char filename[100];
|
|
|
|
#ifndef SIMULATE_RC5
|
|
if (dut.rootp->emu__DOT__tvmode_ntsc) {
|
|
// NTSC
|
|
|
|
if (frame_index > 259) {
|
|
if ((frame_index % 25) == 20)
|
|
press_button_signal = true;
|
|
}
|
|
|
|
} else {
|
|
// PAL
|
|
if (frame_index > 200) {
|
|
if ((frame_index % 25) == 20)
|
|
press_button_signal = true;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
if (press_button_signal) {
|
|
press_button_signal = false;
|
|
release_button_frame = frame_index + 10;
|
|
printf("Press a button!\n");
|
|
fprintf(stderr, "Press a button!\n");
|
|
dut.rootp->emu__DOT__JOY0 = 0b10000;
|
|
}
|
|
|
|
if (release_button_frame == frame_index) {
|
|
printf("Release a button!\n");
|
|
fprintf(stderr, "Release a button!\n");
|
|
dut.rootp->emu__DOT__JOY0 = 0b00000;
|
|
}
|
|
|
|
if (pixel_index > 400) {
|
|
auto current = std::chrono::system_clock::now();
|
|
std::chrono::duration<double> elapsed_seconds = current - start;
|
|
sprintf(filename, "%d/video_%03d.png", instanceid, frame_index);
|
|
write_png_file(filename);
|
|
printf("Written %s %d\n", filename, pixel_index);
|
|
printf("We are at step=%ld\n", step);
|
|
fprintf(stderr, "Written %s after %.2fs\n", filename, elapsed_seconds.count());
|
|
frame_index++;
|
|
}
|
|
pixel_index = 0;
|
|
memset(output_image, 0, sizeof(output_image));
|
|
}
|
|
|
|
// Simulate Audio
|
|
if (dut.rootp->emu__DOT__cditop__DOT__sample_tick44) {
|
|
int16_t sample_l = dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__audio__DOT__fifo_out_left;
|
|
int16_t sample_r = dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__audio__DOT__fifo_out_right;
|
|
fwrite(&sample_l, 2, 1, f_audio_left);
|
|
fwrite(&sample_r, 2, 1, f_audio_right);
|
|
}
|
|
|
|
if (dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__expose_frame) {
|
|
uint32_t addr = dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__frame_adr;
|
|
uint8_t *mem1 = (uint8_t *)&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__memory_core1;
|
|
uint8_t *mem2 = (uint8_t *)&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__memory_core2;
|
|
uint8_t *mem3 = (uint8_t *)&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__video_ram;
|
|
plm_frame2_t frame = *(plm_frame2_t *)(mem1 + addr);
|
|
|
|
// printf("%d %d %x %x %x\n", frame.width, frame.height, frame.y.adr, frame.cr.adr, frame.cb.adr);
|
|
// printf("%x %x %x\n",mem[frame.y.adr], mem[frame.cr.adr],mem[frame.cb.adr]);
|
|
plm_frame_t frame_convert;
|
|
frame_convert.y.data = &mem3[frame.y.adr];
|
|
frame_convert.y.height = frame.y.height;
|
|
frame_convert.y.width = frame.y.width;
|
|
frame_convert.cr.data = &mem3[frame.cr.adr];
|
|
frame_convert.cr.height = frame.cr.height;
|
|
frame_convert.cr.width = frame.cr.width;
|
|
frame_convert.cb.data = &mem3[frame.cb.adr];
|
|
frame_convert.cb.height = frame.cb.height;
|
|
frame_convert.cb.width = frame.cb.width;
|
|
frame_convert.width = frame.width;
|
|
frame_convert.height = frame.height;
|
|
|
|
char bmp_name[20];
|
|
int w = frame.width;
|
|
int h = frame.height;
|
|
uint8_t *pixels = (uint8_t *)malloc(w * h * 3);
|
|
assert(pixels);
|
|
plm_frame_to_bgr(&frame_convert, pixels, w * 3); // BMP expects BGR ordering
|
|
|
|
sprintf(bmp_name, "%06d.bmp", fmv_frame_cnt);
|
|
printf("FMV Writing %s at Fifo Level\n", bmp_name,
|
|
dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__fifo_level);
|
|
fprintf(stderr, "FMV Writing %s at Fifo Level %d\n", bmp_name,
|
|
dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__video__DOT__fifo_level);
|
|
|
|
write_bmp(bmp_name, w, h, pixels);
|
|
|
|
free(pixels);
|
|
fmv_frame_cnt++;
|
|
}
|
|
|
|
if (dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__fmv_data_valid) {
|
|
fwrite(&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__mpeg_data, 1, 1, f_fmv);
|
|
|
|
if (dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__fmv_packet_body) {
|
|
fwrite(&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__mpeg_data, 1, 1, f_fmv_m1v);
|
|
}
|
|
#ifdef TRACE
|
|
if (!do_trace)
|
|
fprintf(stderr, "Trace on!\n");
|
|
do_trace = true;
|
|
#endif
|
|
}
|
|
if (dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__fma_data_valid) {
|
|
fwrite(&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__mpeg_data, 1, 1, f_fma);
|
|
|
|
if (dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__fma_packet_body) {
|
|
fwrite(&dut.rootp->emu__DOT__cditop__DOT__vmpeg_inst__DOT__mpeg_data, 1, 1, f_fma_mp2);
|
|
}
|
|
#ifdef TRACE
|
|
if (!do_trace)
|
|
fprintf(stderr, "Trace on!\n");
|
|
do_trace = true;
|
|
#endif
|
|
}
|
|
|
|
if (pixel_index < size - 6) {
|
|
uint8_t r, g, b;
|
|
|
|
r = g = b = 30;
|
|
|
|
if (dut.VGA_DE) {
|
|
r = dut.VGA_R;
|
|
g = dut.VGA_G;
|
|
b = dut.VGA_B;
|
|
}
|
|
|
|
if (dut.VGA_HS) {
|
|
r += 100;
|
|
}
|
|
|
|
if (dut.VGA_VS) {
|
|
g += 100;
|
|
}
|
|
|
|
output_image[pixel_index++] = r;
|
|
output_image[pixel_index++] = g;
|
|
output_image[pixel_index++] = b;
|
|
}
|
|
}
|
|
|
|
virtual ~CDi() {
|
|
fclose(f_audio_right);
|
|
fclose(f_audio_left);
|
|
fclose(f_fma);
|
|
fclose(f_fma_mp2);
|
|
fclose(f_fmv);
|
|
fclose(f_fmv_m1v);
|
|
fclose(f_uart);
|
|
}
|
|
CDi(int i) {
|
|
instanceid = i;
|
|
|
|
char filename[100];
|
|
sprintf(filename, "%d/audio_left.bin", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_audio_left = fopen(filename, "wb");
|
|
assert(f_audio_left);
|
|
|
|
sprintf(filename, "%d/audio_right.bin", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_audio_right = fopen(filename, "wb");
|
|
assert(f_audio_right);
|
|
|
|
sprintf(filename, "%d/fma.bin", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_fma = fopen(filename, "wb");
|
|
assert(f_fma);
|
|
|
|
sprintf(filename, "%d/fma_mp2.bin", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_fma_mp2 = fopen(filename, "wb");
|
|
assert(f_fma_mp2);
|
|
|
|
sprintf(filename, "%d/fmv.bin", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_fmv = fopen(filename, "wb");
|
|
assert(f_fmv);
|
|
|
|
sprintf(filename, "%d/fmv_m1v.bin", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_fmv_m1v = fopen(filename, "wb");
|
|
assert(f_fmv_m1v);
|
|
|
|
sprintf(filename, "%d/uartlog", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
f_uart = fopen(filename, "wb");
|
|
assert(f_uart);
|
|
|
|
#ifdef TRACE
|
|
dut.trace(&m_trace, 5);
|
|
|
|
if (do_trace) {
|
|
sprintf(filename, "/tmp/waveform.vcd", instanceid);
|
|
fprintf(stderr, "Writing to %s\n", filename);
|
|
m_trace.open(filename);
|
|
}
|
|
#endif
|
|
|
|
dut.eval();
|
|
dut.rootp->emu__DOT__debug_uart_fake_space = false;
|
|
dut.rootp->emu__DOT__img_size = 4096;
|
|
dut.rootp->emu__DOT__rc_eye = 1; // RC Eye signal is idle high
|
|
|
|
dut.rootp->emu__DOT__tvmode_ntsc = false;
|
|
|
|
dut.RESET = 1;
|
|
dut.UART_RXD = 1;
|
|
|
|
// wait for SDRAM to initialize
|
|
for (int y = 0; y < 300; y++) {
|
|
clock();
|
|
}
|
|
|
|
dut.RESET = 0;
|
|
dut.OSD_STATUS = 1;
|
|
|
|
start = std::chrono::system_clock::now();
|
|
#ifdef TRACE
|
|
do_trace = false;
|
|
fprintf(stderr, "Trace off!\n");
|
|
#endif
|
|
|
|
#ifdef SIMULATE_RC5
|
|
rc5_file = fopen("rc5_joy_upwards.csv", "r");
|
|
#endif
|
|
}
|
|
|
|
void reset() {
|
|
dut.RESET = 1;
|
|
clock();
|
|
dut.RESET = 0;
|
|
}
|
|
|
|
void dump_system_memory() {
|
|
char filename[100];
|
|
sprintf(filename, "%d/ramdump.bin", instanceid);
|
|
printf("Writing %s!\n", filename);
|
|
FILE *f = fopen(filename, "wb");
|
|
assert(f);
|
|
fwrite(&dut.rootp->emu__DOT__ram[0], 1, 1024 * 256 * 4, f);
|
|
fclose(f);
|
|
}
|
|
|
|
void dump_slave_memory() {
|
|
#ifdef SLAVE
|
|
char filename[100];
|
|
sprintf(filename, "%d/ramdump_slave.bin", instanceid);
|
|
printf("Writing %s!\n", filename);
|
|
FILE *f = fopen(filename, "wb");
|
|
assert(f);
|
|
fwrite(&dut.rootp->emu__DOT__cditop__DOT__uc68hc05_0__DOT__memory[0], 1, 8192, f);
|
|
fclose(f);
|
|
#endif
|
|
}
|
|
|
|
void dump_cdic_memory() {
|
|
char filename[100];
|
|
sprintf(filename, "%d/ramdump_cdic.bin", instanceid);
|
|
printf("Writing %s!\n", filename);
|
|
FILE *f = fopen(filename, "wb");
|
|
assert(f);
|
|
fwrite(&dut.rootp->emu__DOT__cditop__DOT__cdic_inst__DOT__mem__DOT__ram[0], 2, 8192, f);
|
|
fclose(f);
|
|
}
|
|
};
|
|
|
|
void prepare_apprentice_usa_toc() {
|
|
toc_buffer[0] = {1, 1, 21, 34, 1};
|
|
toc_buffer[1] = {1, 1, 21, 34, 0};
|
|
toc_buffer[2] = {1, 1, 21, 34, 34};
|
|
toc_buffer[3] = {1, 2, 25, 68, 21};
|
|
toc_buffer[4] = {1, 2, 25, 68, 2};
|
|
toc_buffer[5] = {1, 2, 25, 68, 1};
|
|
toc_buffer[6] = {1, 3, 35, 85, 0};
|
|
toc_buffer[7] = {1, 3, 35, 85, 68};
|
|
toc_buffer[8] = {1, 3, 35, 85, 35};
|
|
toc_buffer[9] = {1, 4, 36, 86, 3};
|
|
toc_buffer[10] = {1, 4, 36, 86, 1};
|
|
toc_buffer[11] = {1, 4, 36, 86, 0};
|
|
toc_buffer[12] = {1, 5, 41, 66, 86};
|
|
toc_buffer[13] = {1, 5, 41, 66, 36};
|
|
toc_buffer[14] = {1, 5, 41, 66, 4};
|
|
toc_buffer[15] = {1, 6, 48, 67, 1};
|
|
toc_buffer[16] = {1, 6, 48, 67, 0};
|
|
toc_buffer[17] = {1, 6, 48, 67, 66};
|
|
toc_buffer[18] = {1, 7, 53, 49, 41};
|
|
toc_buffer[19] = {1, 7, 53, 49, 6};
|
|
toc_buffer[20] = {1, 7, 53, 49, 1};
|
|
toc_buffer[21] = {1, 8, 54, 55, 0};
|
|
toc_buffer[22] = {1, 8, 54, 55, 67};
|
|
toc_buffer[23] = {1, 8, 54, 55, 53};
|
|
toc_buffer[24] = {1, 9, 65, 18, 7};
|
|
toc_buffer[25] = {1, 9, 65, 18, 1};
|
|
toc_buffer[26] = {1, 9, 65, 18, 0};
|
|
toc_buffer[27] = {1, 16, 66, 21, 55};
|
|
toc_buffer[28] = {1, 16, 66, 21, 54};
|
|
toc_buffer[29] = {1, 16, 66, 21, 8};
|
|
toc_buffer[30] = {1, 17, 70, 37, 1};
|
|
toc_buffer[31] = {1, 17, 70, 37, 0};
|
|
toc_buffer[32] = {1, 17, 70, 37, 18};
|
|
toc_buffer[33] = {1, 18, 71, 32, 65};
|
|
toc_buffer[34] = {1, 18, 71, 32, 16};
|
|
toc_buffer[35] = {1, 18, 71, 32, 1};
|
|
toc_buffer[36] = {1, 19, 81, 54, 0};
|
|
toc_buffer[37] = {1, 19, 81, 54, 21};
|
|
toc_buffer[38] = {1, 19, 81, 54, 70};
|
|
toc_buffer[39] = {1, 20, 82, 54, 17};
|
|
toc_buffer[40] = {1, 20, 82, 54, 1};
|
|
toc_buffer[41] = {1, 20, 82, 54, 0};
|
|
toc_buffer[42] = {1, 21, 83, 69, 32};
|
|
toc_buffer[43] = {1, 21, 83, 69, 71};
|
|
toc_buffer[44] = {1, 21, 83, 69, 18};
|
|
toc_buffer[45] = {1, 22, 86, 85, 1};
|
|
toc_buffer[46] = {1, 22, 86, 85, 0};
|
|
toc_buffer[47] = {1, 22, 86, 85, 54};
|
|
toc_buffer[48] = {1, 23, 87, 5, 81};
|
|
toc_buffer[49] = {1, 23, 87, 5, 20};
|
|
toc_buffer[50] = {1, 23, 87, 5, 1};
|
|
toc_buffer[51] = {1, 24, 89, 2, 0};
|
|
toc_buffer[52] = {1, 24, 89, 2, 54};
|
|
toc_buffer[53] = {1, 24, 89, 2, 83};
|
|
toc_buffer[54] = {1, 25, 89, 37, 21};
|
|
toc_buffer[55] = {1, 25, 89, 37, 1};
|
|
toc_buffer[56] = {1, 25, 89, 37, 0};
|
|
toc_buffer[57] = {1, 32, 96, 0, 85};
|
|
toc_buffer[58] = {1, 32, 96, 0, 86};
|
|
toc_buffer[59] = {1, 32, 96, 0, 22};
|
|
toc_buffer[60] = {1, 33, 96, 34, 1};
|
|
toc_buffer[61] = {1, 33, 96, 34, 0};
|
|
toc_buffer[62] = {1, 33, 96, 34, 5};
|
|
toc_buffer[63] = {1, 34, 96, 87, 87};
|
|
toc_buffer[64] = {1, 34, 96, 87, 24};
|
|
toc_buffer[65] = {1, 34, 96, 87, 1};
|
|
toc_buffer[66] = {1, 160, 1, 0, 0};
|
|
toc_buffer[67] = {1, 160, 1, 0, 2};
|
|
toc_buffer[68] = {1, 160, 1, 0, 89};
|
|
toc_buffer[69] = {1, 161, 34, 0, 25};
|
|
toc_buffer[70] = {1, 161, 34, 0, 1};
|
|
toc_buffer[71] = {1, 161, 34, 0, 0};
|
|
toc_buffer[72] = {1, 162, 21, 34, 0};
|
|
toc_buffer[73] = {1, 162, 21, 34, 96};
|
|
toc_buffer[74] = {1, 162, 21, 34, 32};
|
|
|
|
toc_entry_count = 75;
|
|
}
|
|
|
|
void prepare_lucky_luke_europe_toc() {
|
|
toc_buffer[0] = {1, 1, 34, 25, 1};
|
|
toc_buffer[1] = {1, 1, 34, 25, 0};
|
|
toc_buffer[2] = {1, 1, 34, 25, 25};
|
|
toc_buffer[3] = {1, 2, 37, 32, 34};
|
|
toc_buffer[4] = {1, 2, 37, 32, 2};
|
|
toc_buffer[5] = {1, 2, 37, 32, 1};
|
|
toc_buffer[6] = {1, 3, 41, 2, 0};
|
|
toc_buffer[7] = {1, 3, 41, 2, 32};
|
|
toc_buffer[8] = {1, 3, 41, 2, 41};
|
|
toc_buffer[9] = {1, 4, 50, 19, 3};
|
|
toc_buffer[10] = {1, 4, 50, 19, 1};
|
|
toc_buffer[11] = {1, 4, 50, 19, 0};
|
|
toc_buffer[12] = {1, 5, 53, 70, 19};
|
|
toc_buffer[13] = {1, 5, 53, 70, 50};
|
|
toc_buffer[14] = {1, 5, 53, 70, 4};
|
|
toc_buffer[15] = {1, 6, 56, 4, 1};
|
|
toc_buffer[16] = {1, 6, 56, 4, 0};
|
|
toc_buffer[17] = {1, 6, 56, 4, 70};
|
|
toc_buffer[18] = {1, 7, 57, 37, 53};
|
|
toc_buffer[19] = {1, 7, 57, 37, 6};
|
|
toc_buffer[20] = {1, 7, 57, 37, 1};
|
|
toc_buffer[21] = {1, 8, 64, 86, 0};
|
|
toc_buffer[22] = {1, 8, 64, 86, 4};
|
|
toc_buffer[23] = {1, 8, 64, 86, 57};
|
|
toc_buffer[24] = {1, 9, 66, 41, 7};
|
|
toc_buffer[25] = {1, 9, 66, 41, 1};
|
|
toc_buffer[26] = {1, 9, 66, 41, 0};
|
|
toc_buffer[27] = {1, 16, 67, 72, 86};
|
|
toc_buffer[28] = {1, 16, 67, 72, 64};
|
|
toc_buffer[29] = {1, 16, 67, 72, 8};
|
|
toc_buffer[30] = {1, 17, 68, 41, 1};
|
|
toc_buffer[31] = {1, 17, 68, 41, 0};
|
|
toc_buffer[32] = {1, 17, 68, 41, 41};
|
|
toc_buffer[33] = {1, 18, 68, 82, 66};
|
|
toc_buffer[34] = {1, 18, 68, 82, 16};
|
|
toc_buffer[35] = {1, 18, 68, 82, 1};
|
|
toc_buffer[36] = {1, 19, 69, 84, 0};
|
|
toc_buffer[37] = {1, 19, 69, 84, 72};
|
|
toc_buffer[38] = {1, 19, 69, 84, 68};
|
|
toc_buffer[39] = {1, 20, 71, 25, 17};
|
|
toc_buffer[40] = {1, 20, 71, 25, 1};
|
|
toc_buffer[41] = {1, 20, 71, 25, 0};
|
|
toc_buffer[42] = {1, 21, 72, 69, 82};
|
|
toc_buffer[43] = {1, 21, 72, 69, 68};
|
|
toc_buffer[44] = {1, 21, 72, 69, 18};
|
|
toc_buffer[45] = {1, 22, 81, 37, 1};
|
|
toc_buffer[46] = {1, 22, 81, 37, 0};
|
|
toc_buffer[47] = {1, 22, 81, 37, 84};
|
|
toc_buffer[48] = {1, 160, 1, 0, 69};
|
|
toc_buffer[49] = {1, 160, 1, 0, 20};
|
|
toc_buffer[50] = {1, 160, 1, 0, 1};
|
|
toc_buffer[51] = {1, 161, 22, 0, 0};
|
|
toc_buffer[52] = {1, 161, 22, 0, 25};
|
|
toc_buffer[53] = {1, 161, 22, 0, 72};
|
|
toc_buffer[54] = {1, 162, 34, 25, 21};
|
|
toc_buffer[55] = {1, 162, 34, 25, 1};
|
|
toc_buffer[56] = {1, 162, 34, 25, 0};
|
|
|
|
toc_entry_count = 57;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
// Initialize Verilators variables
|
|
Verilated::commandArgs(argc, argv);
|
|
|
|
#ifdef TRACE
|
|
if (do_trace)
|
|
Verilated::traceEverOn(true);
|
|
#endif
|
|
|
|
struct sigaction sa;
|
|
sa.sa_sigaction = signal_handler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGINT, &sa, NULL);
|
|
sigaction(SIGUSR1, &sa, NULL);
|
|
|
|
int machineindex = 0;
|
|
|
|
if (argc >= 2) {
|
|
machineindex = atoi(argv[1]);
|
|
fprintf(stderr, "Machine is %d\n", machineindex);
|
|
}
|
|
|
|
switch (machineindex) {
|
|
case 0:
|
|
f_cd_bin = fopen("images/Dragon_s_Lair_US.bin", "rb");
|
|
break;
|
|
case 1:
|
|
f_cd_bin = fopen("images/LuckyLuke.bin", "rb");
|
|
prepare_lucky_luke_europe_toc();
|
|
break;
|
|
case 2:
|
|
f_cd_bin = fopen("images/LuckyLuke.bin", "rb");
|
|
prepare_lucky_luke_europe_toc();
|
|
break;
|
|
case 3:
|
|
f_cd_bin = fopen("images/Nobelia (USA).bin", "rb");
|
|
break;
|
|
case 4:
|
|
f_cd_bin = fopen("images/fmvtest_only_audio.bin", "rb");
|
|
break;
|
|
case 5:
|
|
f_cd_bin = fopen("images/fmvtest.bin", "rb");
|
|
break;
|
|
case 6:
|
|
f_cd_bin = fopen("images/FMVTEST.BIN", "rb");
|
|
break;
|
|
case 7:
|
|
f_cd_bin = fopen("images/mpeg_only_audio.bin", "rb");
|
|
break;
|
|
case 8:
|
|
f_cd_bin = fopen("images/Dragon_s_Lair_US.bin", "rb");
|
|
prepare_apprentice_usa_toc();
|
|
break;
|
|
}
|
|
|
|
assert(f_cd_bin);
|
|
|
|
CDi machine(machineindex);
|
|
|
|
machine.dut.rootp->emu__DOT__config_auto_play = argc >= 3 ? 1 : 0;
|
|
|
|
while (status == 0) {
|
|
machine.modelstep();
|
|
}
|
|
|
|
machine.modelstep();
|
|
machine.modelstep();
|
|
machine.modelstep();
|
|
machine.dump_system_memory();
|
|
machine.dump_slave_memory();
|
|
|
|
fclose(f_cd_bin);
|
|
|
|
fprintf(stderr, "Closing...\n");
|
|
fflush(stdout);
|
|
|
|
return 0;
|
|
}
|