From e4c2a047fa094e79cd8dd984062fe510c9d779c2 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 25 Feb 2024 13:27:39 +0800 Subject: [PATCH] example: add gdrom_test This successfully reads the first 17 sectors of the first data track of a CD. --- example/dump_ram.cpp | 28 +++++ example/example.mk | 17 ++- example/gdrom_test.cpp | 253 ++++++++++++++++++++++++++++++++++++++++ example/software_ta.cpp | 8 +- example/software_ta.hpp | 15 +++ gdrom_bits.hpp | 43 +++++++ sh7091/serial.cpp | 9 ++ sh7091/serial.hpp | 2 + 8 files changed, 369 insertions(+), 6 deletions(-) create mode 100644 example/dump_ram.cpp create mode 100644 example/gdrom_test.cpp create mode 100644 gdrom_bits.hpp diff --git a/example/dump_ram.cpp b/example/dump_ram.cpp new file mode 100644 index 0000000..985e78f --- /dev/null +++ b/example/dump_ram.cpp @@ -0,0 +1,28 @@ +#include + +#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(sum); +} + +void main() +{ + // dump the first 64k of system memory + dump_ram(system_memory, 0x10000); + + + while (1); +} diff --git a/example/example.mk b/example/example.mk index abae35a..e77505e 100644 --- a/example/example.mk +++ b/example/example.mk @@ -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) diff --git a/example/gdrom_test.cpp b/example/gdrom_test.cpp new file mode 100644 index 0000000..353066b --- /dev/null +++ b/example/gdrom_test.cpp @@ -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(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(gdrom_if.interrupt_reason & 1); + + serial::string("bsy1: "); + serial::integer(gdrom_if.status & gdrom::status::bsy); + for (int i = 0; i < 6; i++) + gdrom_if.data = 0; + serial::integer(gdrom_if.status & gdrom::status::bsy); + + while ((gdrom_if.status & (gdrom::status::bsy | gdrom::status::drq)) != 0); + serial::string("bsy2: "); + serial::integer(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(&data[0]); + for (int i = 0; i < 6; i++) { + gdrom_if.data = buf[i]; + } + + serial::string("status1: "); + serial::integer(gdrom_if.status); + while ((gdrom_if.status & gdrom::status::bsy) != 0) { + serial::integer(gdrom_if.status); + for (int i = 0; i < 10000000; i++) { asm volatile ("nop;"); } + }; + serial::string("status2: "); + serial::integer(gdrom_if.status); + + serial::string("byte_control: "); + serial::integer(gdrom_if.byte_control_high, ' '); + serial::integer(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(&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(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(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(gdrom_if.byte_control_high, ' '); + serial::integer(gdrom_if.byte_control_low); + } + serial::string("read bytes: "); + serial::integer(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); +} diff --git a/example/software_ta.cpp b/example/software_ta.cpp index 9c9e18c..4385d74 100644 --- a/example/software_ta.cpp +++ b/example/software_ta.cpp @@ -210,6 +210,7 @@ void main() qq.c = rotate(q.c, theta); qq.d = rotate(q.d, theta); + auto mem = reinterpret_cast(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(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(); diff --git a/example/software_ta.hpp b/example/software_ta.hpp index a089c7d..8c59d61 100644 --- a/example/software_ta.hpp +++ b/example/software_ta.hpp @@ -116,6 +116,21 @@ void object_pointer_blocks(volatile uint32_t * mem, const quad& quad) } } +template +void opb_checkerboard_pattern(volatile uint32_t * mem) +{ + auto block = reinterpret_cast *>(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; diff --git a/gdrom_bits.hpp b/gdrom_bits.hpp new file mode 100644 index 0000000..19287d1 --- /dev/null +++ b/gdrom_bits.hpp @@ -0,0 +1,43 @@ +#include + +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; + +} + +} diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index b254239..2d4c611 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -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(num_buf, length, n); + character(num_buf[0]); + character(num_buf[1]); +} + template void integer(const T n, const char end) { diff --git a/sh7091/serial.hpp b/sh7091/serial.hpp index e8c5443..27a9ad8 100644 --- a/sh7091/serial.hpp +++ b/sh7091/serial.hpp @@ -6,6 +6,8 @@ void character(const char c); void string(const char * s); +void hexlify(const uint8_t n); + template void integer(const T n, const char end);