diff --git a/common.mk b/common.mk index dfb8362..4e7986e 100644 --- a/common.mk +++ b/common.mk @@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(dir $(MAKEFILE_PATH)) LIB ?= . -OPT ?= -O0 +OPT ?= -O3 GENERATED ?= AARCH = --isa=sh4 --little diff --git a/example/aica_gdrom.cpp b/example/aica_gdrom.cpp index 3251480..803a672 100644 --- a/example/aica_gdrom.cpp +++ b/example/aica_gdrom.cpp @@ -2,9 +2,16 @@ #include "sh7091/serial.hpp" #include "systembus.hpp" #include "systembus_bits.hpp" + #include "aica/aica.hpp" -extern void * _audio_pcm_start __asm("_binary_audio_pcm_start"); +#include "gdrom/gdrom.hpp" +#include "gdrom/gdrom_bits.hpp" +#include "gdrom/command_packet_format.hpp" +#include "gdrom/toc.hpp" + +#include "iso9660/primary_volume_descriptor.hpp" +#include "iso9660/directory_record.hpp" extern void * _binary_start __asm("_binary_example_arm_sh4_interrupt_bin_start"); extern void * _binary_size __asm("_binary_example_arm_sh4_interrupt_bin_size"); @@ -12,6 +19,9 @@ extern void * _binary_size __asm("_binary_example_arm_sh4_interrupt_bin_size"); constexpr uint32_t mcipd__sh4_interrupt = (1 << 5); constexpr uint32_t scipd__arm_interrupt = (1 << 5); +constexpr uint32_t sectors_per_chunk = 16; +constexpr uint32_t chunk_size = 2048 * sectors_per_chunk; + void aica_wait_write() { while (ffst::aica_internal_write_buffer(system.FFST)); @@ -27,20 +37,17 @@ void aica_wait_read() }; } -void fill_chunk(volatile uint32_t * chunk, const uint32_t segment_index) +void aica_fill_chunk(volatile uint32_t * dest_chunk, const uint32_t * src_chunk, const uint32_t size) { - const uint32_t * audio_pcm = reinterpret_cast(&_audio_pcm_start); - const uint32_t * segment = &audio_pcm[(segment_index * 128 * 2) / 4]; - - for (int i = 0; i < (128 * 2) / 4; i++) { + for (uint32_t i = 0; i < size / 4; i++) { if (i % 8 == 0) aica_wait_write(); - chunk[i] = segment[i]; + dest_chunk[i] = src_chunk[i]; } } -static volatile uint32_t (* chunk)[2][(128 * 2) / 4]; +static volatile uint32_t (* chunk)[2][chunk_size / 4]; -void aica_init(uint32_t& chunk_index, uint32_t& segment_index) +void aica_init(uint32_t& chunk_index, const uint32_t * src_chunk) { const uint32_t * binary = reinterpret_cast(&_binary_start); const uint32_t binary_size = reinterpret_cast(&_binary_size); @@ -55,19 +62,20 @@ void aica_init(uint32_t& chunk_index, uint32_t& segment_index) } } - chunk = reinterpret_cast(&aica_wave_memory[0x001ff000 / 4]); + chunk = reinterpret_cast(&aica_wave_memory[0x001f0000 / 4]); serial::integer(reinterpret_cast(&(*chunk)[0][0])); serial::integer(reinterpret_cast(&(*chunk)[1][0])); - fill_chunk(&(*chunk)[chunk_index][0], segment_index); + aica_fill_chunk(&(*chunk)[chunk_index][0], + src_chunk, + chunk_size); chunk_index = (chunk_index + 1) % 2; - segment_index += 1; aica_wait_write(); aica_sound.common.vreg_armrst = aica::vreg_armrst::ARMRST(0); } -void aica_step(uint32_t& chunk_index, uint32_t& segment_index) +void aica_step(uint32_t& chunk_index, const uint32_t * src_chunk) { aica_wait_read(); { // wait for interrupt from arm @@ -76,23 +84,271 @@ void aica_step(uint32_t& chunk_index, uint32_t& segment_index) } { // fill the requested chunk - fill_chunk(&(*chunk)[chunk_index][0], segment_index); + aica_fill_chunk(&(*chunk)[chunk_index][0], + src_chunk, + chunk_size); chunk_index = (chunk_index + 1) % 2; - segment_index += 1; - if (segment_index >= 3440) segment_index = 0; } } +// gdrom + +void gdrom_pio_data(const uint8_t * data) +{ + while ((gdrom::status::bsy(gdrom_if.status) | gdrom::status::drq(gdrom_if.status)) != 0); + + gdrom_if.features = gdrom::features::dma::disable; + gdrom_if.drive_select = gdrom::drive_select::drive_select + | gdrom::drive_select::lun(0); + + gdrom_if.command = gdrom::command::code::packet_command; + while (gdrom::status::drq(gdrom_if.status) == 0); + + const uint16_t * buf = reinterpret_cast(&data[0]); + for (int i = 0; i < 6; i++) { + gdrom_if.data = buf[i]; + } + + while (gdrom::status::bsy(gdrom_if.status) != 0); +} + +void gdrom_read_data(uint16_t * buf, const uint32_t length) +{ + //serial::string("read_data drq interrupt_reason: "); + //serial::integer(gdrom::status::drq(gdrom_if.status), ' '); + //serial::integer(gdrom_if.interrupt_reason); + for (uint32_t i = 0; i < (length / 2); i++) { + buf[i] = gdrom_if.data; + } +} + +uint32_t gdrom_toc__get_data_track_fad() +{ + auto packet = gdrom_command_packet_format::get_toc(0, // single-density + 0x0198 // maximum toc length + ); + serial::string("get_toc\n"); + gdrom_pio_data(packet._data()); + + serial::string("byte_count: "); + serial::integer(gdrom_if.byte_count()); + uint16_t buf[gdrom_if.byte_count() / 2]; + gdrom_read_data(buf, gdrom_if.byte_count()); + + serial::string("status: "); + serial::integer(gdrom_if.status); + + auto toc = reinterpret_cast(buf); + for (int i = 0; i < 99; i++) { + if (toc->track[i].fad() == 0xffffff) + break; + serial::string("track "); + serial::integer(i); + serial::integer(toc->track[i].fad()); + } + + // assume track 1 is the correct track + return toc->track[1].fad(); +} + +uint32_t gdrom_cd_read2(uint16_t * buf, + const uint32_t starting_address, + const uint32_t transfer_length, + const uint32_t next_address) +{ + 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 = (data_select << 4) | (expected_data_type << 1) | (parameter_type << 0); + + auto packet = gdrom_command_packet_format::cd_read2(data, + starting_address, + transfer_length, + next_address); + //serial::string("cd_read\n"); + //serial::string("starting_address: "); + //serial::integer(starting_address); + //serial::string("transfer_length: "); + //serial::integer(transfer_length); + //serial::string("next_address: "); + //serial::integer(next_address); + gdrom_pio_data(packet._data()); + + uint32_t length = 0; + while ((gdrom::status::drq(gdrom_if.status)) != 0) { + const uint32_t byte_count = gdrom_if.byte_count(); + length += byte_count; + gdrom_read_data(buf, byte_count); + + serial::string("read status: "); + serial::integer(gdrom_if.status); + + while ((gdrom::status::bsy(gdrom_if.status)) != 0); // wait for drive to become not-busy + } + + serial::string("read length: "); + serial::integer(length); + return length; +} + +void gdrom_unlock() +{ + // gdrom unlock undocumented register + g1_if.GDUNLOCK = 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]; + } +} + +bool str_equal(const uint8_t * a, + const uint32_t a_len, + const char * b, + const uint32_t b_len) +{ + if (a_len != b_len) + return false; + + uint32_t len = a_len; + + while (len != 0) { + if (*a++ != *b++) + return false; + + len--; + } + + return true; +} + +struct extent +{ + const uint32_t location; + const uint32_t data_length; +}; + +struct extent gdrom_find_file() +{ + const uint32_t fad = gdrom_toc__get_data_track_fad(); + serial::character('\n'); + + const uint32_t primary_volume_descriptor = fad + 16; + uint16_t buf[2048 / 2]; + const uint32_t length0 = gdrom_cd_read2(buf, + primary_volume_descriptor, // starting address + 1, // one sector; 2048 bytes + primary_volume_descriptor + 1 // next address + ); + serial::character('\n'); + + auto pvd = reinterpret_cast(&buf[0]); + auto root_dr = reinterpret_cast(&pvd->directory_record_for_root_directory[0]); + + serial::string("primary volume descriptor:\n"); + serial::string(" standard_identifier: "); + serial::string(pvd->standard_identifier, 5); + serial::character('\n'); + serial::string(" root directory record:\n"); + serial::string(" location of extent: "); + serial::integer(root_dr->location_of_extent.get()); + serial::string(" data length: "); + serial::integer(root_dr->data_length.get()); + + serial::character('\n'); + + const uint32_t root_directory_extent = root_dr->location_of_extent.get(); + const uint32_t length1 = gdrom_cd_read2(buf, + root_directory_extent + 150, // 150? + 1, // one sector; 2048 bytes + root_directory_extent + 151 // 150? + ); + serial::character('\n'); + + auto buf8 = reinterpret_cast(buf); + uint32_t offset = 0; + while (true) { + serial::string("directory entry offset: "); + serial::integer(offset); + + auto dr = reinterpret_cast(&buf8[offset]); + if (dr->length_of_directory_record == 0) + break; + + serial::string(" length_of_directory_record: "); + serial::integer(dr->length_of_directory_record); + serial::string(" length_of_file_identifier: "); + serial::integer(dr->length_of_file_identifier); + serial::string(" file_identifier: "); + serial::string(dr->file_identifier, dr->length_of_file_identifier); + serial::character('\n'); + + bool equal = str_equal(dr->file_identifier, dr->length_of_file_identifier, + "REIGN.PCM;1", 11); + + if (dr->file_flags == 0) { + serial::string(" location_of_extent: "); + serial::integer(dr->location_of_extent.get()); + serial::string(" data_length: "); + serial::integer(dr->data_length.get()); + + if (equal) { + serial::string("FOUND\n"); + return { + dr->location_of_extent.get(), + dr->data_length.get() + }; + } + } + + offset += dr->length_of_directory_record; + } + + return { 0 , 0 }; +} + +void gdrom_read_chunk(uint32_t * buf, const uint32_t extent, const uint32_t num_extents) +{ + const uint32_t length1 = gdrom_cd_read2(reinterpret_cast(buf), + extent + 150, // 150? + num_extents, // one sector; 2048 bytes + extent + 150 + num_extents // 150? + ); +} + +void next_segment(const struct extent& extent, uint32_t& segment_index) +{ + segment_index += sectors_per_chunk; + if ((segment_index * 2048) > extent.data_length) + segment_index = 0; +} + void main() { uint32_t chunk_index = 0; uint32_t segment_index = 0; - aica_init(chunk_index, segment_index); + gdrom_unlock(); + const auto extent = gdrom_find_file(); + uint32_t gdrom_buf[chunk_size / 4]; + gdrom_read_chunk(gdrom_buf, extent.location + segment_index, sectors_per_chunk); + next_segment(extent, segment_index); + + aica_init(chunk_index, &gdrom_buf[0]); + + serial::string("aica wave memory:\n"); + while (aica_wave_memory[0] == 0xeaffffff) { aica_wait_read(); }; + aica_wait_read(); serial::integer(aica_wave_memory[0]); + aica_wait_read(); serial::integer(aica_wave_memory[1]); while (1) { - aica_step(chunk_index, segment_index); + //serial::integer(chunk_index); + gdrom_read_chunk(gdrom_buf, extent.location + segment_index, sectors_per_chunk); + next_segment(extent, segment_index); + + aica_step(chunk_index, &gdrom_buf[0]); } while (1); diff --git a/example/arm/Makefile b/example/arm/Makefile index 8523927..5b855ff 100644 --- a/example/arm/Makefile +++ b/example/arm/Makefile @@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(dir $(MAKEFILE_PATH)) LIB ?= . -OPT ?= -Og +OPT ?= -O3 GENERATED ?= AARCH = -march=armv4 -mlittle-endian diff --git a/example/arm/main.lds b/example/arm/main.lds index a08ac95..3775665 100644 --- a/example/arm/main.lds +++ b/example/arm/main.lds @@ -1,8 +1,8 @@ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x1ff000 - buffers : ORIGIN = 0x001ff000, LENGTH = 0x1000 + ram : ORIGIN = 0x00000000, LENGTH = 0x1f0000 + buffers : ORIGIN = 0x001f0000, LENGTH = 0x10000 } SECTIONS { diff --git a/example/arm/sh4_interrupt.cpp b/example/arm/sh4_interrupt.cpp index 78b38fc..04cb4ad 100644 --- a/example/arm/sh4_interrupt.cpp +++ b/example/arm/sh4_interrupt.cpp @@ -2,8 +2,11 @@ extern volatile uint32_t dram[0x200000] __asm("dram"); +constexpr uint32_t sectors_per_chunk = 16; +constexpr uint32_t chunk_size = 2048 * sectors_per_chunk; + __attribute__((section(".buffers.chunk"))) -static uint32_t chunk[2][(128 * 2) / 4]; +static uint32_t chunk[2][chunk_size / 4]; void request_chunk() { @@ -36,7 +39,7 @@ void main() aica_sound.channel[0].LPCTL(1); aica_sound.channel[0].PCMS(0); aica_sound.channel[0].LSA(0); - aica_sound.channel[0].LEA(128); + aica_sound.channel[0].LEA(chunk_size / 2); aica_sound.channel[0].D2R(0x0); aica_sound.channel[0].D1R(0x0); aica_sound.channel[0].RR(0x0); @@ -58,8 +61,8 @@ void main() | aica::mono_mem8mb_dac18b_ver_mvol::MVOL(0xf) // 15/15 volume ; - constexpr uint32_t tactl = 0; // increment once every 1 samples - constexpr uint32_t tima = 256 - 128; // interrupt after 1 count + constexpr uint32_t tactl = 7; // increment once every 1 samples + constexpr uint32_t tima = 256 - 128; // interrupt after 128 samples dram[0] = reinterpret_cast(&chunk[0][0]); dram[1] = reinterpret_cast(&chunk[1][0]); @@ -75,18 +78,16 @@ void main() | aica::tactl_tima::TIMA(tima); aica_sound.common.scire = timer_a_interrupt; - uint32_t index = 0; + uint32_t sample = 0; while (1) { if (aica_sound.common.SCIPD() & timer_a_interrupt) { aica_sound.channel[0].SA(reinterpret_cast(&chunk[next_chunk][0])); aica_sound.common.tactl_tima = aica::tactl_tima::TACTL(tactl) - | aica::tactl_tima::TIMA(tima); - - aica_sound.common.scire = timer_a_interrupt; - + | aica::tactl_tima::TIMA(tima); next_chunk = (next_chunk + 1) % 2; request_chunk(); - //dram[0] = (0xEE << 24) | index++; + + aica_sound.common.scire = timer_a_interrupt; } } } diff --git a/example/example.mk b/example/example.mk index b75b192..1fe2dff 100644 --- a/example/example.mk +++ b/example/example.mk @@ -307,9 +307,10 @@ example/maple_analog.elf: $(START_OBJ) $(MAPLE_ANALOG_OBJ) SERIAL_TRANSFER_OBJ = \ example/serial_transfer.o \ + sh7091/serial.o \ serial_load.o -example/serial_transfer.elf: LDSCRIPT = $(LIB)/alt.lds +example/serial_transfer.elf: LDSCRIPT = $(LIB)/main.lds example/serial_transfer.elf: $(START_OBJ) $(SERIAL_TRANSFER_OBJ) INTERRUPT_OBJ = \ @@ -376,8 +377,7 @@ example/aica.elf: $(START_OBJ) $(AICA_OBJ) AICA_GDROM_OBJ = \ example/aica_gdrom.o \ sh7091/serial.o \ - example/arm/sh4_interrupt.bin.o \ - audio.pcm.o + example/arm/sh4_interrupt.bin.o example/aica_gdrom.elf: LDSCRIPT = $(LIB)/alt.lds example/aica_gdrom.elf: $(START_OBJ) $(AICA_GDROM_OBJ) diff --git a/example/gdrom_iso9660.cpp b/example/gdrom_iso9660.cpp index ec2264e..e03e5cd 100644 --- a/example/gdrom_iso9660.cpp +++ b/example/gdrom_iso9660.cpp @@ -81,8 +81,6 @@ uint32_t cd_read(uint16_t * buf, auto packet = gdrom_command_packet_format::cd_read(data, starting_address, transfer_length); - - auto arst = packet._data(); serial::string("cd_read\n"); serial::string("starting_address: "); serial::integer(starting_address);