example: add gdrom_test

This successfully reads the first 17 sectors of the first data track
of a CD.
This commit is contained in:
Zack Buhman 2024-02-25 13:27:39 +08:00
parent c851070604
commit e4c2a047fa
8 changed files with 369 additions and 6 deletions

28
example/dump_ram.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <cstdint>
#include "memorymap.hpp"
#include "sh7091/serial.hpp"
void dump_ram(const volatile uint32_t * mem, const uint32_t len)
{
uint32_t sum = 0;
for (uint32_t i = 0; i < ; i++) {
uint8_t n = mem[i];
sum += n;
serial::hexlify(n);
if ((i & 0xf) == 0xf)
serial::character('\n');
}
serial::character('\n');
serial::integer<uint32_t>(sum);
}
void main()
{
// dump the first 64k of system memory
dump_ram(system_memory, 0x10000);
while (1);
}

View File

@ -326,12 +326,18 @@ DUMP_OBJECT_LIST_OBJ = \
holly/region_array.o \
holly/background.o \
holly/ta_fifo_polygon_converter.o \
sh7091/serial.o \
libm.o
sh7091/serial.o
example/dump_object_list.elf: LDSCRIPT = $(LIB)/alt.lds
example/dump_object_list.elf: $(START_OBJ) $(DUMP_OBJECT_LIST_OBJ)
DUMP_RAM_OBJ = \
example/dump_ram.o \
sh7091/serial.o
example/dump_ram.elf: LDSCRIPT = $(LIB)/alt.lds
example/dump_ram.elf: $(START_OBJ) $(DUMP_RAM_OBJ)
SOFTWARE_TA_OBJ = \
example/software_ta.o \
vga.o \
@ -344,3 +350,10 @@ SOFTWARE_TA_OBJ = \
example/software_ta.elf: LDSCRIPT = $(LIB)/alt.lds
example/software_ta.elf: $(START_OBJ) $(SOFTWARE_TA_OBJ)
GDROM_TEST_OBJ = \
example/gdrom_test.o \
sh7091/serial.o
example/gdrom_test.elf: LDSCRIPT = $(LIB)/alt.lds
example/gdrom_test.elf: $(START_OBJ) $(GDROM_TEST_OBJ)

253
example/gdrom_test.cpp Normal file
View File

@ -0,0 +1,253 @@
#include "gdrom.hpp"
#include "gdrom_bits.hpp"
#include "memorymap.hpp"
#include "sh7091/serial.hpp"
union data {
uint8_t u8[2];
uint16_t u16;
};
static_assert((sizeof (data)) == 2);
void test_unit()
{
serial::string("test_unit\n");
// wait for BSY == 0 && DRQ == 0
while ((gdrom_if.status & (gdrom::status::bsy | gdrom::status::drq)) != 0) {
serial::integer<uint8_t>(gdrom_if.status);
for (int i = 0; i < 1000000; i++) { asm volatile ("nop;"); }
};
serial::string("bsy | drq == 0\n");
gdrom_if.command = 0xa0; // packet command
while ((gdrom_if.status & gdrom::status::drq) == 0);
serial::string("drq != 0; CoD: ");
serial::integer<uint8_t>(gdrom_if.interrupt_reason & 1);
serial::string("bsy1: ");
serial::integer<uint8_t>(gdrom_if.status & gdrom::status::bsy);
for (int i = 0; i < 6; i++)
gdrom_if.data = 0;
serial::integer<uint8_t>(gdrom_if.status & gdrom::status::bsy);
while ((gdrom_if.status & (gdrom::status::bsy | gdrom::status::drq)) != 0);
serial::string("bsy2: ");
serial::integer<uint8_t>(gdrom_if.status);
serial::string("\n");
}
void pio_data(const uint8_t * data)
{
while ((gdrom_if.status & (gdrom::status::bsy | gdrom::status::drq)) != 0);
serial::string("bsy | drq == 0\n");
gdrom_if.features = 0; // not DMA
gdrom_if.drive_select = 0b1010'0000; // LUN 0
gdrom_if.command = 0xa0; // packet command
// CoD
//serial::string("wait CoD\n");
while ((gdrom_if.interrupt_reason & 0b11) != gdrom::interrupt_reason::cod);
//serial::string("done CoD\n");
while ((gdrom_if.status & gdrom::status::drq) == 0);
serial::string("drq == 1\n");
const uint16_t * buf = reinterpret_cast<const uint16_t *>(&data[0]);
for (int i = 0; i < 6; i++) {
gdrom_if.data = buf[i];
}
serial::string("status1: ");
serial::integer<uint8_t>(gdrom_if.status);
while ((gdrom_if.status & gdrom::status::bsy) != 0) {
serial::integer<uint8_t>(gdrom_if.status);
for (int i = 0; i < 10000000; i++) { asm volatile ("nop;"); }
};
serial::string("status2: ");
serial::integer<uint8_t>(gdrom_if.status);
serial::string("byte_control: ");
serial::integer<uint8_t>(gdrom_if.byte_control_high, ' ');
serial::integer<uint8_t>(gdrom_if.byte_control_low);
}
void read_data(uint32_t length)
{
uint16_t read[length / 2];
for (uint32_t i = 0; i < (length / 2); i++) {
read[i] = gdrom_if.data;
}
const uint8_t * read_buf = reinterpret_cast<const uint8_t *>(&read[0]);
for (uint32_t i = 0; i < length; i++) {
serial::hexlify(read_buf[i]);
serial::character(' ');
if ((i & 0xf) == 0xf)
serial::character('\n');
}
serial::character('\n');
serial::string("status: ");
serial::integer<uint8_t>(gdrom_if.status);
}
void req_stat()
{
const uint8_t data[12] = {
0x10, // req_stat
0x00,
0x00, // starting_address
0x00,
0x0a, // allocation_length
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
serial::string("\nreq_stat\n");
pio_data(data);
read_data(0xa);
}
void req_mode()
{
const uint8_t data[12] = {
0x11, // req_mode
0x00,
0x00, // starting_address
0x00,
0x20, // allocation_length
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
serial::string("\nreq_mode\n");
pio_data(data);
read_data(0x20);
}
void get_toc()
{
const uint8_t data[12] = {
0x14, // GET_TOC
(0 << 0), // single density
0x0,
0xff, // allocation length msb
0xff, // allocation length lsb
0x00, // 5
0x00, // 6
0x00, // 7
0x00, // 8
0x00, // 9
0x00, // 10
0x00, // 11
};
serial::string("\nget_toc\n");
pio_data(data);
const uint32_t length = (gdrom_if.byte_control_high << 8) | (gdrom_if.byte_control_low << 0);
// 102 entries ; 4 bytes per entry, 408 bytes (0x0198)
read_data(length);
}
/* TOC:
01 00 00 96 (track 1 information)
- audio track
- FAD track start: 0x000096
41 00 2e 4c (track 2 information)
- data track
- FAD track start: 0x002e4c
01 01 00 00 (start track information)
01: first track is audio track
01: first track is track number 1
41 02 00 00 (end track information)
41: last track is data track
02: last track is track number 2
41 00 2f 7c (lead-out information)
*/
void cd_read()
{
// CD-ROM XA mode 2 form 1
const uint8_t data_select = 0b0010; // data
const uint8_t expected_data_type = 0b100; // XA mode 2 form 1
const uint8_t parameter_type = 0b0; // FAD specified
const uint8_t data[12] = {
0x31, // CD_READ
(data_select << 4) | (expected_data_type << 1) | (parameter_type << 0),
0x00, // starting address (msb)
0x2e, //
0x4c, // starting address (lsb)
0x00, // 5
0x00, // transfer length (msb)
0x11, // transfer length (lsb)
0x00, // next address (msb)
0x2e, // 9
0x4c, // next address (lsb)
0x00, // 11
};
serial::string("\ncd_read\n");
pio_data(data);
uint32_t read = 0;
while ((gdrom_if.status & 0x08) != 0) {
serial::string("offset: ");
serial::integer<uint32_t>(read);
const uint32_t length = (gdrom_if.byte_control_high << 8) | (gdrom_if.byte_control_low << 0);
// 102 entries ; 4 bytes per entry, 408 bytes (0x0198)
read_data(length);
read += length;
serial::string("byte_control: ");
serial::integer<uint8_t>(gdrom_if.byte_control_high, ' ');
serial::integer<uint8_t>(gdrom_if.byte_control_low);
}
serial::string("read bytes: ");
serial::integer<uint32_t>(read);
}
void main()
{
// gdrom unlock undocumented register
*((volatile unsigned long *)0xa05f74e4) = 0x1fffff;
// Without this read from system_boot_rom, the read value of
// gdrom_if.status is always 0xff
for(uint32_t i = 0; i < 0x200000 / 4; i++) {
(void)system_boot_rom[i];
}
test_unit();
req_stat();
req_mode();
get_toc();
cd_read();
while (1);
}

View File

@ -210,6 +210,7 @@ void main()
qq.c = rotate(q.c, theta);
qq.d = rotate(q.d, theta);
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory32);
if (hardware_ta) {
ta_polygon_converter_init(opb_size.total(),
ta_alloc,
@ -219,11 +220,10 @@ void main()
ta_polygon_converter_transfer(ta_parameter_buf, ta_parameter_size);
ta_wait_opaque_list();
} else {
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory32);
software_ta::object_pointer_blocks<8>(&mem->object_list[0], qq);
software_ta::isp_tsp_parameters(&mem->isp_tsp_parameters[0], qq);
software_ta::object_pointer_blocks<8>(mem->object_list, qq);
software_ta::isp_tsp_parameters(mem->isp_tsp_parameters, qq);
}
software_ta::opb_checkerboard_pattern<8>(mem->object_list);
core_start_render(frame_ix, num_frames);
core_wait_end_of_render_video();

View File

@ -116,6 +116,21 @@ void object_pointer_blocks(volatile uint32_t * mem, const quad& quad)
}
}
template <int N>
void opb_checkerboard_pattern(volatile uint32_t * mem)
{
auto block = reinterpret_cast<volatile object_pointer_block<N> *>(mem);
for (uint32_t y = 0; y < tile_height; y++) {
for (uint32_t x = 0; x < tile_width; x++) {
if (((x + (y & 1)) & 1) == 0) continue;
auto& opb = block[y * tile_width + x];
opb.pointer[0] = object_list_data::pointer_type::object_pointer_block_link
| object_list_data::object_pointer_block_link::end_of_list;
}
}
}
struct __untextured_quad_vertex {
float x;
float y;

43
gdrom_bits.hpp Normal file
View File

@ -0,0 +1,43 @@
#include <cstdint>
namespace gdrom {
namespace status {
constexpr uint8_t bsy = (1 << 7);
constexpr uint8_t drdy = (1 << 6);
constexpr uint8_t df = (1 << 5);
constexpr uint8_t dsc = (1 << 4);
constexpr uint8_t drq = (1 << 3);
constexpr uint8_t corr = (1 << 2);
constexpr uint8_t check = (1 << 0);
}
namespace interrupt_reason {
constexpr uint8_t io = (1 << 1);
constexpr uint8_t cod = (1 << 0);
}
namespace command {
constexpr uint8_t test_unit = 0x00;
constexpr uint8_t req_stat = 0x10;
constexpr uint8_t req_mode = 0x11;
constexpr uint8_t set_mode = 0x12;
constexpr uint8_t req_error = 0x13;
constexpr uint8_t get_toc = 0x14;
constexpr uint8_t req_ses = 0x15;
constexpr uint8_t cd_open = 0x16;
constexpr uint8_t cd_play = 0x20;
constexpr uint8_t cd_seek = 0x21;
constexpr uint8_t cd_scan = 0x22;
constexpr uint8_t cd_read = 0x30;
constexpr uint8_t cd_read2 = 0x31;
constexpr uint8_t get_scd = 0x40;
}
}

View File

@ -47,6 +47,15 @@ void string(const char * s)
}
}
void hexlify(const uint8_t n)
{
constexpr uint32_t length = 2;
char num_buf[length];
string::hex<char>(num_buf, length, n);
character(num_buf[0]);
character(num_buf[1]);
}
template <typename T>
void integer(const T n, const char end)
{

View File

@ -6,6 +6,8 @@ void character(const char c);
void string(const char * s);
void hexlify(const uint8_t n);
template <typename T>
void integer(const T n, const char end);