diff --git a/assert.h b/assert.h new file mode 100644 index 0000000..ea38f1d --- /dev/null +++ b/assert.h @@ -0,0 +1,24 @@ +#pragma once + +#if defined(__dreamcast__) +#include "sh7091/serial.hpp" +#define print__character serial::character +#define print__string serial::string +#define print__integer serial::integer +#else +#error "unknown platform" +#endif + +#define assert(b) \ + do { \ + if (!(b)) { \ + print__string(__FILE__); \ + print__character(':'); \ + print__integer(__LINE__, ' '); \ + print__string(__func__); \ + print__string(": assertion failed: "); \ + print__string(#b); \ + print__character('\n'); \ + while (1); \ + } \ + } while (0); diff --git a/base.mk b/base.mk index 08062f1..b715af4 100644 --- a/base.mk +++ b/base.mk @@ -102,6 +102,12 @@ endef %.vq.o: %.vq $(BUILD_BINARY_O) +%.mod.h: %.mod + $(BUILD_BINARY_H) + +%.mod.o: %.mod + $(BUILD_BINARY_O) + %.o: %.s $(AS) $(AARCH) $(AFLAGS) $(DEBUG) $< -o $@ diff --git a/example/example.mk b/example/example.mk index 2033a71..d06eb5a 100644 --- a/example/example.mk +++ b/example/example.mk @@ -976,3 +976,32 @@ FOG_OBJ = \ example/fog.elf: LDSCRIPT = $(LIB)/main.lds example/fog.elf: $(START_OBJ) $(FOG_OBJ) + +BOIDS_OBJ = \ + example/boids.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + holly/video_output.o \ + sh7091/serial.o \ + $(LIBGCC) + +example/boids.elf: LDSCRIPT = $(LIB)/main.lds +example/boids.elf: $(START_OBJ) $(BOIDS_OBJ) + + +MOD_OBJ = \ + example/mod.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + holly/video_output.o \ + sh7091/serial.o \ + mod/mod.o \ + mod/getfunk/getfunk.mod.o \ + $(LIBGCC) + +example/mod.elf: LDSCRIPT = $(LIB)/main.lds +example/mod.elf: $(START_OBJ) $(MOD_OBJ) diff --git a/example/mod.cpp b/example/mod.cpp new file mode 100644 index 0000000..5b2a17a --- /dev/null +++ b/example/mod.cpp @@ -0,0 +1,84 @@ +#include "aica/aica.hpp" +#include "memorymap.hpp" +#include "sh7091/serial.hpp" +#include "systembus.hpp" +#include "systembus_bits.hpp" + +#include "mod/mod.hpp" +#include "mod/getfunk/getfunk.mod.h" + +void wait() +{ + 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)) { + ffst = system.FFST; + }; +} + +void main() +{ + serial::init(0); + + const uint8_t * start = reinterpret_cast(&_binary_mod_getfunk_getfunk_mod_start); + const uint32_t size = reinterpret_cast(&_binary_mod_getfunk_getfunk_mod_size); + + struct reader r = { + .buf = start, + .length = (int)size, + .ix = 0, + }; + + struct mod mod; + + parse_mod_file(&r, &mod); + + serial::string(mod.tag, 4); + + serial::integer(r.ix); + serial::integer(r.ix); + serial::integer(r.ix); + + // reset ARM + wait(); aica_sound.common.vreg_armrst = aica::vreg_armrst::ARMRST(1); + // disable DSP / ARM / slot access ; enable SH4 access + wait(); aica_sound.common.dmea0_mrwinh = aica::dmea0_mrwinh::MRWINH(0b0111); + + volatile uint32_t * slot = reinterpret_cast(0xa0700000); + for (uint32_t i = 0; i < (sizeof (struct aica_channel)) * 64 / 4; i++) { + wait(); slot[i] = 0; + } + + volatile uint32_t * dsp = reinterpret_cast(0xa0700000 + 0x3000); + for (int i = 0; i < 0xb00 / 4; i++) { + wait(); dsp[i] = 0; + } + + uint32_t * buf32 = (uint32_t *)&start[r.ix]; + struct sample * sample = &mod.samples[0es); + wait(); aica_sound.channel[0].D2R(0x0); + wait(); aica_sound.channel[0].D1R(0x0); + wait(); aica_sound.channel[0].RR(0x0); + wait(); aica_sound.channel[0].AR(0x1f); + + wait(); aica_sound.channel[0].OCT(-2); + wait(); aica_sound.channel[0].FNS(0); + wait(); aica_sound.channel[0].DISDL(0xf); + wait(); aica_sound.channel[0].DIPAN(0x0); + + wait(); aica_sound.channel[0].Q(0b00100); + wait(); aica_sound.channel[0].TL(0); + wait(); aica_sound.channel[0].LPOFF(1); + + wait(); 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 + ; + + wait(); aica_sound.channel[0].KYONEX(1); + + while (1); +} diff --git a/mod/getfunk/getfunk.mod b/mod/getfunk/getfunk.mod new file mode 100644 index 0000000..ffe76df Binary files /dev/null and b/mod/getfunk/getfunk.mod differ diff --git a/mod/getfunk/getfunk.mod.h b/mod/getfunk/getfunk.mod.h new file mode 100644 index 0000000..37e4660 --- /dev/null +++ b/mod/getfunk/getfunk.mod.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_mod_getfunk_getfunk_mod_start __asm("_binary_mod_getfunk_getfunk_mod_start"); +extern uint32_t _binary_mod_getfunk_getfunk_mod_end __asm("_binary_mod_getfunk_getfunk_mod_end"); +extern uint32_t _binary_mod_getfunk_getfunk_mod_size __asm("_binary_mod_getfunk_getfunk_mod_size"); + +#ifdef __cplusplus +} +#endif diff --git a/mod/mod.cpp b/mod/mod.cpp new file mode 100644 index 0000000..03f2358 --- /dev/null +++ b/mod/mod.cpp @@ -0,0 +1,98 @@ +#include "mod.hpp" +#include "assert.h" + +static const uint8_t * reader_s(struct reader * r, int length) +{ + const uint8_t * ptr = &r->buf[r->ix]; + r->ix += length; + return ptr; +} + +static void reader_bytes(struct reader * r, int length, uint8_t * dst) +{ + const uint8_t * ptr = reader_s(r, length); + for (int i = 0; i < length; i++) + dst[i] = ptr[i]; +} + +static int reader_u8(struct reader * r) +{ + const uint8_t * ptr = reader_s(r, 1); + return *ptr; +} + +static int reader_u16(struct reader * r) +{ + const uint8_t * ptr = reader_s(r, 2); + int value = (((uint32_t)ptr[0]) << 8) | (((uint32_t)ptr[1]) << 0); + return value; +} + +static void parse_sample(struct reader * r, struct sample * s) +{ + s->name = reader_s(r, 22); + s->length = reader_u16(r); + s->nibble = reader_u8(r); + s->volume = reader_u8(r); + s->repeat_offset = reader_u16(r); + s->repeat_length = reader_u16(r); +} + +static int parse_num_patterns(uint8_t * table) +{ + int max = 0; + for (int i = 0; i < 128; i++) { + if ((int)table[i] > max) { + max = table[i]; + } + } + return max + 1; +} + +static void parse_channel(const uint8_t * data, struct channel * c) +{ + uint32_t w = ((uint32_t)data[0] >> 4) & 0xf; + uint32_t x = ((uint32_t)data[1]) | (((uint32_t)data[0] & 0xf) << 8); + uint32_t y = ((uint32_t)data[2] >> 4) & 0xf; + uint32_t z = ((uint32_t)data[3]) | (((uint32_t)data[2] & 0xf) << 8); + + c->sample = (w << 4) | y; + c->parameter = x; + c->effect = z; +} + +static void parse_pattern(struct reader * r, struct pattern * pattern) +{ + const uint8_t * raw_pattern = reader_s(r, 1024); + for (int division = 0; division < 64; division++) { + int ix = division * 16; + parse_channel(&raw_pattern[ix+0 ], &pattern->division[division][0]); + parse_channel(&raw_pattern[ix+4 ], &pattern->division[division][1]); + parse_channel(&raw_pattern[ix+8 ], &pattern->division[division][2]); + parse_channel(&raw_pattern[ix+12], &pattern->division[division][3]); + } +} + +void parse_mod_file(struct reader * r, struct mod * mod) +{ + mod->title = reader_s(r, 20); + + for (int i = 0; i < 31; i++) { + parse_sample(r, &mod->samples[i]); + } + + mod->song_positions = reader_u8(r); + mod->ignored = reader_u8(r); + reader_bytes(r, 128, mod->pattern_table); + + assert(r->ix == 0x438); + reader_bytes(r, 4, mod->tag); + + assert(mod->tag[0] == 'M' && mod->tag[1] == '.' && + mod->tag[2] == 'K' && mod->tag[3] == '.'); + + int num_patterns = parse_num_patterns(mod->pattern_table); + for (int i = 0; i < num_patterns; i++) { + parse_pattern(r, &mod->patterns[i]); + } +} diff --git a/mod/mod.hpp b/mod/mod.hpp new file mode 100644 index 0000000..f541e8d --- /dev/null +++ b/mod/mod.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "stdint.h" + +struct sample +{ + const uint8_t * name; + int length; + int nibble; + int volume; + int repeat_offset; + int repeat_length; +}; + +struct channel { + uint16_t sample; + uint16_t parameter; + uint16_t effect; + uint16_t _pad; +}; + +struct pattern +{ + struct channel division[64][4]; +}; + +struct mod +{ + const uint8_t * title; + struct sample samples[31]; + int song_positions; + int ignored; + uint8_t pattern_table[128]; + uint8_t tag[4]; + struct pattern patterns[128]; +}; + +struct reader +{ + const uint8_t * buf; + const int length; + int ix; +}; + +void parse_mod_file(struct reader * r, struct mod * mod);