example/aica_gdrom: initial

aica_gdrom currently copies from system ram to AICA ram, 128 bytes at
a time, synchronized with the AICA sample timer.
This commit is contained in:
Zack Buhman 2024-03-01 19:38:47 +08:00
parent 73a685face
commit 0aea1d0db2
7 changed files with 207 additions and 46 deletions

View File

@ -14,7 +14,7 @@ void wait()
void wait_read()
{
uint32_t ffst = ~0;
uint32_t ffst = system.FFST;
while ( ffst::holly_cpu_if_block_internal_write_buffer(ffst)
| ffst::holly_g2_if_block_internal_write_buffer(ffst)
| ffst::aica_internal_write_buffer(ffst)) {

View File

@ -1,20 +1,25 @@
#include "memorymap.hpp"
#include "aica/aica.hpp"
#include "sh7091/serial.hpp"
#include "systembus.hpp"
#include "systembus_bits.hpp"
#include "aica/aica.hpp"
extern void * _binary_start __asm("_binary_example_arm_channel_bin_start");
extern void * _binary_size __asm("_binary_example_arm_channel_bin_size");
extern void * _audio_pcm_start __asm("_binary_audio_pcm_start");
void wait()
extern void * _binary_start __asm("_binary_example_arm_sh4_interrupt_bin_start");
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);
void aica_wait_write()
{
while (ffst::aica_internal_write_buffer(system.FFST));
}
void wait_read()
void aica_wait_read()
{
uint32_t ffst = ~0;
uint32_t ffst = system.FFST;
while ( ffst::holly_cpu_if_block_internal_write_buffer(ffst)
| ffst::holly_g2_if_block_internal_write_buffer(ffst)
| ffst::aica_internal_write_buffer(ffst)) {
@ -22,41 +27,73 @@ void wait_read()
};
}
void main()
void fill_chunk(volatile uint32_t * chunk, const uint32_t segment_index)
{
const uint32_t * audio_pcm = reinterpret_cast<const uint32_t *>(&_audio_pcm_start);
const uint32_t * segment = &audio_pcm[(segment_index * 128 * 2) / 4];
for (int i = 0; i < (128 * 2) / 4; i++) {
if (i % 8 == 0) aica_wait_write();
chunk[i] = segment[i];
}
}
static volatile uint32_t (* chunk)[2][(128 * 2) / 4];
void aica_init(uint32_t& chunk_index, uint32_t& segment_index)
{
const uint32_t * binary = reinterpret_cast<uint32_t *>(&_binary_start);
const uint32_t binary_size = reinterpret_cast<uint32_t>(&_binary_size);
wait(); aica.common.reg_2c00 = 1;
wait(); aica.common.reg_2880 = 0;
aica_wait_write(); aica_sound.common.vreg_armrst = aica::vreg_armrst::ARMRST(1);
aica_wait_write(); aica_sound.common.dmea0_mrwinh = aica::dmea0_mrwinh::MRWINH(0);
for (uint32_t i = 0; i < binary_size / 4; i++) {
// copy
aica_wave_memory[i] = binary[i];
if (i % 8 == 7) wait();
}
wait(); aica.common.reg_2c00 = 0;
serial::integer<uint32_t>(aica_wave_memory[0]);
wait(); aica.common.MSLC(0);
serial::string("mrwinh: ");
wait_read();
serial::integer<uint8_t>(aica.common.MRWINH());
while (1) {
wait_read();
serial::string("sgc: ");
serial::integer<uint8_t>(aica.common.SGC(), ' ');
serial::string("; ca: ");
serial::integer<uint8_t>(aica.common.CA(), ' ');
serial::string("; eg: ");
serial::integer<uint8_t>(aica.common.EG(), ' ');
serial::string("; lp: ");
serial::integer<uint8_t>(aica.common.LP(), ' ');
serial::character('\n');
for (int i = 0; i < 10000000; i++) {
asm volatile ("nop");
while (aica_wave_memory[i] != binary[i]) {
aica_wait_write();
aica_wave_memory[i] = binary[i];
}
}
chunk = reinterpret_cast<decltype (chunk)>(&aica_wave_memory[0x001ff000 / 4]);
serial::integer<uint32_t>(reinterpret_cast<uint32_t>(&(*chunk)[0][0]));
serial::integer<uint32_t>(reinterpret_cast<uint32_t>(&(*chunk)[1][0]));
fill_chunk(&(*chunk)[chunk_index][0], segment_index);
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)
{
aica_wait_read();
{ // wait for interrupt from arm
while ((aica_sound.common.MCIPD() & mcipd__sh4_interrupt) == 0) { aica_wait_read(); };
aica_wait_write(); aica_sound.common.mcire = mcipd__sh4_interrupt;
}
{ // fill the requested chunk
fill_chunk(&(*chunk)[chunk_index][0], segment_index);
chunk_index = (chunk_index + 1) % 2;
segment_index += 1;
if (segment_index >= 3440) segment_index = 0;
}
}
void main()
{
uint32_t chunk_index = 0;
uint32_t segment_index = 0;
aica_init(chunk_index, segment_index);
while (1) {
aica_step(chunk_index, segment_index);
}
while (1);
}

View File

@ -21,6 +21,9 @@ include base.mk
channel.elf: LDSCRIPT = main.lds
channel.elf: start.o channel.o audio.pcm.o
sh4_interrupt.elf: LDSCRIPT = main.lds
sh4_interrupt.elf: start.o sh4_interrupt.o
clean:
find -P \
-regextype posix-egrep \

View File

@ -22,7 +22,6 @@ void main()
aica_sound.channel[0].KYONB(1);
aica_sound.channel[0].LPCTL(1);
aica_sound.channel[0].PCMS(0);
aica_sound.channel[0].SA(sine_addr);
aica_sound.channel[0].LSA(0);
aica_sound.channel[0].LEA(128);
aica_sound.channel[0].D2R(0x0);
@ -39,26 +38,38 @@ void main()
aica_sound.channel[0].TL(0);
aica_sound.channel[0].LPOFF(1);
aica_sound.common.MVOL(0xf);
aica_sound.common.mono_mem8mb_dac18b_ver_mvol =
aica::mono_mem8mb_dac18b_ver_mvol::MONO(0) // enable panpots
| aica::mono_mem8mb_dac18b_ver_mvol::MEM8MB(0) // 16Mbit SDRAM
| aica::mono_mem8mb_dac18b_ver_mvol::DAC18B(0) // 16-bit DAC
| aica::mono_mem8mb_dac18b_ver_mvol::MVOL(0xf) // 15/15 volume
;
uint32_t segment = 0;
aica_sound.common.TACTL(7); // increment once every 128 samples
aica_sound.common.TIMA(255);
aica_sound.channel[0].KYONEX(1);
dram[0] = 0x11223344;
dram[1] = sine_addr;
constexpr uint32_t timer_a_interrupt = (1 << 6);
aica_sound.common.scire = timer_a_interrupt;
uint32_t next_sa = sine_addr;
bool started = 0;
while (1) {
if (aica_sound.common.SCIPD() & timer_a_interrupt) {
if (!started || (aica_sound.common.SCIPD() & timer_a_interrupt)) {
aica_sound.channel[0].SA(next_sa);
aica_sound.common.tactl_tima =
aica::tactl_tima::TACTL(0) // increment once every 128 samples
| aica::tactl_tima::TIMA(256 - 128) // interrupt after 128 counts
;
if (!started) { aica_sound.channel[0].KYONEX(1); started = 1; }
aica_sound.common.scire = timer_a_interrupt;
aica_sound.common.TIMA(255);
dram[1] = next_sa;
segment += 1;
if (segment >= 3440) segment = 0;
uint32_t sa = sine_addr + (128 * 2) * segment;
dram[1] = sa;
aica_sound.channel[0].SA(sa);
next_sa = sine_addr + (128 * 2) * segment;
}
}
}

View File

@ -1,7 +1,8 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 0x200000
ram : ORIGIN = 0x00000000, LENGTH = 0x1ff000
buffers : ORIGIN = 0x001ff000, LENGTH = 0x1000
}
SECTIONS
{
@ -40,6 +41,14 @@ SECTIONS
*(COMMON)
} > ram
. = ORIGIN(buffers);
.buffers ALIGN(4) (NOLOAD) : SUBALIGN(4)
{
*(.buffers)
*(.buffers.*)
} > buffers
INCLUDE "../../debug.lds"
INCLUDE "arm.lds"
}

View File

@ -0,0 +1,92 @@
#include "aica/aica.hpp"
extern volatile uint32_t dram[0x200000] __asm("dram");
__attribute__((section(".buffers.chunk")))
static uint32_t chunk[2][(128 * 2) / 4];
void request_chunk()
{
constexpr uint32_t mcipd__sh4_interrupt = (1 << 5);
aica_sound.common.mcipd = mcipd__sh4_interrupt;
}
void wait_sh4_response()
{
constexpr uint32_t scipd__arm_interrupt = (1 << 5);
while ((aica_sound.common.SCIPD() & scipd__arm_interrupt) == 0) {
}
aica_sound.common.scire = scipd__arm_interrupt;
}
extern "C"
void main()
{
volatile uint32_t * slot = reinterpret_cast<volatile uint32_t*>(0x00800000);
for (uint32_t i = 0; i < (sizeof (struct aica_channel)) * 64 / 4; i++) {
slot[i] = 0;
}
volatile uint32_t * dsp = reinterpret_cast<volatile uint32_t*>(0x00803000);
for (int i = 0; i < 0xb00 / 4; i++) {
dsp[i] = 0;
}
aica_sound.channel[0].KYONB(1);
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].D2R(0x0);
aica_sound.channel[0].D1R(0x0);
aica_sound.channel[0].RR(0x0);
aica_sound.channel[0].AR(0x1f);
aica_sound.channel[0].OCT(0);
aica_sound.channel[0].FNS(0);
aica_sound.channel[0].DISDL(0xf);
aica_sound.channel[0].DIPAN(0x0);
aica_sound.channel[0].Q(0b00100);
aica_sound.channel[0].TL(0);
aica_sound.channel[0].LPOFF(1);
aica_sound.common.mono_mem8mb_dac18b_ver_mvol =
aica::mono_mem8mb_dac18b_ver_mvol::MONO(0) // enable panpots
| aica::mono_mem8mb_dac18b_ver_mvol::MEM8MB(0) // 16Mbit SDRAM
| aica::mono_mem8mb_dac18b_ver_mvol::DAC18B(0) // 16-bit DAC
| 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
dram[0] = reinterpret_cast<uint32_t>(&chunk[0][0]);
dram[1] = reinterpret_cast<uint32_t>(&chunk[1][0]);
uint32_t next_chunk = 0;
aica_sound.channel[0].SA(reinterpret_cast<const uint32_t>(&chunk[next_chunk][0]));
aica_sound.channel[0].KYONEX(1);
next_chunk = (next_chunk + 1) % 2;
request_chunk();
constexpr uint32_t timer_a_interrupt = (1 << 6);
aica_sound.common.tactl_tima = aica::tactl_tima::TACTL(tactl)
| aica::tactl_tima::TIMA(tima);
aica_sound.common.scire = timer_a_interrupt;
uint32_t index = 0;
while (1) {
if (aica_sound.common.SCIPD() & timer_a_interrupt) {
aica_sound.channel[0].SA(reinterpret_cast<const uint32_t>(&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;
next_chunk = (next_chunk + 1) % 2;
request_chunk();
//dram[0] = (0xEE << 24) | index++;
}
}
}

View File

@ -368,7 +368,16 @@ example/gdrom_iso9660.elf: $(START_OBJ) $(GDROM_ISO9660_OBJ)
AICA_OBJ = \
example/aica.o \
sh7091/serial.o \
example/arm/channel.bin.o \
example/arm/channel.bin.o
example/aica.elf: LDSCRIPT = $(LIB)/alt.lds
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/aica_gdrom.elf: LDSCRIPT = $(LIB)/alt.lds
example/aica_gdrom.elf: $(START_OBJ) $(AICA_GDROM_OBJ)