From 62a47e236d5c573ea8a2d3071be5a4d2e14d7ea6 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 3 Jul 2025 16:24:38 -0500 Subject: [PATCH] fully implement repeat; fixed numerous small bugs --- Makefile | 2 +- font/icons.data | Bin 1024 -> 1024 bytes font/icons.pgm | Bin 2107 -> 2107 bytes src/framebuffer.cpp | 4 ++ src/graphics.cpp | 44 ++++++++++++++++++--- src/graphics.hpp | 2 + src/icons.cpp | 8 ++-- src/icons.hpp | 1 + src/interpreter.cpp | 19 ++++++--- src/interpreter.hpp | 4 ++ src/main.cpp | 17 +++++++- src/playlist.cpp | 6 ++- src/playlist.hpp | 4 +- src/scene/emulator/sound.cpp | 2 +- src/scene/logo/sound.cpp | 2 +- src/scene/scene.cpp | 12 ++++++ src/scene/tracker/scene.cpp | 73 +++++++++++++++++++++++++---------- 17 files changed, 155 insertions(+), 45 deletions(-) diff --git a/Makefile b/Makefile index 7c1915a..dc39c65 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ all: xm_player.elf -OPT = -O1 +OPT = -O2 MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) LIB ?= $(MAKEFILE_PATH)/dreamcast diff --git a/font/icons.data b/font/icons.data index f584a8b25939af2f4bd9c21941b1bc4d485eacdb..3c66050ace840649489bdcdcdf2a25050ee51974 100644 GIT binary patch literal 1024 zcmaiy3zkD62t#!Tvj5FCH-Poo&Xm*g_#_xV5fN+2m5mWG##!mk{hbqJ8(mnP-*e{7 zPQ;Vfb*&l5XnshCbMaIywqg;^`~zPFt7X82&-M2>qrnoGb2*Uz^*!Kp2$zlio;~8O z_g5vK0VL@qe&pJ_s(Z@3^4%D*6faH+zV5>JW9B~9T%ImGa4h>4djM&TPB|SWK6Qrx)xgbr}i_aW`r2bX{&cenvg$y>S$KMc{#G_ z`^W+KQp_awDwJxW-!_MCs>CMH4a&PQgDcd4Q>)Lx`dAYa^>OcResKolSVw&#QlRgt IUx-zD0X=~nhyVZp literal 1024 zcmaKr3lfAd2t(T&l>1+H^Y|#OuFR|!NFY$x%xo<^(#9|wqem)pzUKs4Miy52XPr4C zW47}uuAYXB;+u51FP@^w)>(w^Kkyk4UpU!;r<4bas5dZN-lx%+*uOmS&9ZH^-*PxF zd3La}JLm43{I2)(t3G_HuqpUl;Sv~pH=%?x0cBpB;cihK%h~twkw5W36_XsO)AzPv z>MqIaf_+};K|O@RLL|l@{Aw>xKNy;5s%iH1k@S7~A{gQRfCAp0%k=48=Es_s0xH22 zv0v9I*XyE}jPzaf?Y|WHxR3a6L?osbFW2sD`bd?|(jAiru1S44I@cf3C;Z&|*VtL> E2f4W$+yDRo diff --git a/font/icons.pgm b/font/icons.pgm index 1d6c8967d58b09599f29c642f89cd6bdcee61e20..d8316414762255d18123451a29f594f59733be91 100644 GIT binary patch literal 2107 zcmdUv%}T>i5QSamDK5CSXllg03vp4&D<}pjNR|2nK7GvmpGizw+!;vc%$@np+?xw+ zo9eXO?7N4L?x{R}m)pBdTfVye`}TEL>ea>hYJFYW`%QU!`FuXx?y9THvaYMTX{x?I z89hBeya;m0y%hzuWCMUe2JZxm+(J&U0@8S2QXv8N;2p_Ic<-Kwa9H4tim1BY)0c^s{>j>C}3 Owd1mIIIjQyb^QR*wST<; literal 2107 zcmdUs%SyyR5Jg?*D;iuoXvTrK;Md1g-Ky%_!8~whLsGXM=T>K? zZK~6BbL<{Ix~KH`oo?@TZTjkt@B7z7sy7$so9%UK?|13#<@5P$f2gi5)3&barm6b= zWORBxS|o|wMgtlTNS|sXiI*x;^gY$uA`d3^xP`${*F0ve+uP-a{m$j+4g`@Tzl@9& z90(%0hR4rB5Xp7CI1oe_YCwpQ@(m)|?zXX{^N*tuOivgVlVA9&Yz-`dY zPW&m^q*Ts^B|~JTR1A?YgX~HWN#hNaMpRsz1wkZfdXUjjVc=SRSPdScq{+LGI^`I} zF+H0T=W=!)OY?|B6mxS**)J_^=SXN(I{H}9RQ*86eCESQgqmt!X84IQ)L{)DnX~_2 zrKEDo1h*P$vRZ>lYoH1e?}8UM9g){?0!HfZNq$UB@UrvQXDzQ66La+eWxFisRayJp Smm+`LUwFBUpQT;@wEqK~#A(w2 diff --git a/src/framebuffer.cpp b/src/framebuffer.cpp index 68467ab..79e82e3 100644 --- a/src/framebuffer.cpp +++ b/src/framebuffer.cpp @@ -20,11 +20,15 @@ void framebuffer_init() | fb_y_clip::fb_y_clip_min(0); // read + while (spg_status::vsync(holly.SPG_STATUS)); + while (!spg_status::vsync(holly.SPG_STATUS)); holly.FB_R_SIZE = fb_r_size::fb_modulus(1) | fb_r_size::fb_y_size(y_size - 1) | fb_r_size::fb_x_size((x_size * bytes_per_pixel) / 4 - 1); + holly.FB_R_SOF1 = texture_memory_alloc.framebuffer[0].start; + holly.FB_R_CTRL = fb_r_ctrl::vclk_div::pclk_vclk_1 | fb_r_ctrl::fb_depth::_565_rgb_16bit | fb_r_ctrl::fb_enable; diff --git a/src/graphics.cpp b/src/graphics.cpp index f216281..29e3c3e 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -27,9 +27,11 @@ #include "cursor.hpp" #include "ta_parameter.hpp" +#include "sh7091/sh7091.hpp" + static volatile int ta_in_use = 0; static volatile int core_in_use = 0; -static volatile int next_frame = 0; +volatile int next_frame = 0; static volatile int framebuffer_ix = 0; static volatile int next_frame_ix = 0; @@ -91,16 +93,51 @@ void transfer_palettes() holly.PT_ALPHA_REF = 0xf0; } +static inline void zeroize_ta_fifo_texture_memory_32byte(void * dst, int length) +{ + uint32_t out_addr = (uint32_t)dst; + sh7091.CCN.QACR0 = ((reinterpret_cast(out_addr) >> 24) & 0b11100); + sh7091.CCN.QACR1 = ((reinterpret_cast(out_addr) >> 24) & 0b11100); + + volatile uint32_t * base = &store_queue[(out_addr & 0x03ffffe0) / 4]; + + length = (length + 31) & ~31; // round up to nearest multiple of 32 + while (length > 0) { + base[0] = 0xc5f7c5f7; + base[1] = 0xc5f7c5f7; + base[2] = 0xc5f7c5f7; + base[3] = 0xc5f7c5f7; + base[4] = 0xc5f7c5f7; + base[5] = 0xc5f7c5f7; + base[6] = 0xc5f7c5f7; + base[7] = 0xc5f7c5f7; + asm volatile ("pref @%0" + : // output + : "r" (&base[0]) // input + : "memory"); + length -= 32; + base += 8; + } +} + void graphics_init() { holly.SOFTRESET = softreset::pipeline_soft_reset | softreset::ta_soft_reset; holly.SOFTRESET = 0; + system.LMMODE0 = 1; // 32-bit address space + system.LMMODE1 = 1; // 32-bit address space + + int length = 640 * 480 * 2; + uint32_t offset = texture_memory_alloc.framebuffer[0].start; + void * dst = reinterpret_cast(&ta_fifo_texture_memory[offset / 4]); + zeroize_ta_fifo_texture_memory_32byte(dst, length); + scaler_init(); core_init(); core_param_init(); - spg_set_mode_640x480(); + //spg_set_mode_640x480(); framebuffer_init(); background_parameter2(texture_memory_alloc.background[1].start, @@ -186,7 +223,4 @@ void graphics_event(ta_multiwriter& multi) ta_polygon_converter_writeback(multi.op.buf, multi.op.offset); ta_polygon_converter_transfer(multi.op.buf, multi.op.offset); } - - while (next_frame == 0); - next_frame = 0; } diff --git a/src/graphics.hpp b/src/graphics.hpp index 12cec05..781acf1 100644 --- a/src/graphics.hpp +++ b/src/graphics.hpp @@ -7,6 +7,8 @@ constexpr int ta_cont_count = 1; +extern volatile int next_frame; + void graphics_interrupt(uint32_t istnrm); void graphics_init(); void graphics_event(ta_multiwriter& multi); diff --git a/src/icons.cpp b/src/icons.cpp index eb4a7b5..f31bb81 100644 --- a/src/icons.cpp +++ b/src/icons.cpp @@ -8,10 +8,10 @@ namespace icons { constexpr float texture_height = 1.0 / 32.0; const icon icons[] = { - [ff] = icon(18, 19, 9, 7), - [fff] = icon(14, 19, 13, 7), - [next] = icon(45, 12, 19, 11), - [prev] = icon(45, 0, 19, 11), + [ff] = icon(17, 19, 9, 7), + [fff] = icon(13, 19, 13, 7), + [next] = icon(46, 12, 19, 11), + [prev] = icon(44, 0, 19, 11), [rr] = icon(0, 19, 9, 7), [rrr] = icon(0, 19, 13, 7), [play] = icon(0, 0, 17, 17), diff --git a/src/icons.hpp b/src/icons.hpp index 36d50c6..ca956c7 100644 --- a/src/icons.hpp +++ b/src/icons.hpp @@ -29,6 +29,7 @@ namespace icons { { uint32_t texture_size = tsp_instruction_word::texture_u_size::from_int(64) | tsp_instruction_word::texture_v_size::from_int(32) + | tsp_instruction_word::clamp_uv::uv | tsp_instruction_word::dst_alpha_instr::inverse_src_alpha; global_polygon_textured(writer, diff --git a/src/interpreter.cpp b/src/interpreter.cpp index c61a021..3fdefe7 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -5,6 +5,7 @@ #include "interpreter.hpp" #include "sound.hpp" +#include "playlist.hpp" namespace interpreter { @@ -187,8 +188,17 @@ static inline void next_pattern() if (state.pattern_order_table_index < 0) state.pattern_order_table_index = state.xm.song_length - 1; - if (state.pattern_order_table_index >= state.xm.song_length) - state.pattern_order_table_index = 0; + if (state.pattern_order_table_index >= state.xm.song_length) { + if (state.repeat) { + state.pattern_order_table_index = 0; + } else if (state.reverse) { + playlist::prev(false); + return; + } else { + playlist::next(false); + return; + } + } printf("pattern_order_table_index: %d\n", state.pattern_order_table_index); state.pattern_index = state.xm.header->pattern_order_table[state.pattern_order_table_index]; @@ -341,8 +351,7 @@ void stop_sound() wait(); bool kyonb = aica_sound.channel[ch].KYONB() != 0; wait(); aica_sound.channel[ch].KYONB(0); - wait(); aica_sound.channel[ch].RR(0x1f); - state.channel[ch].keyon = kyonb ? 255 : 0; + //state.channel[ch].keyon = kyonb ? 255 : 0; } wait(); aica_sound.channel[0].KYONEX(1); } @@ -374,8 +383,6 @@ void deferred_load(int buf) state.deferred_load_tick = aica_clock_multiplier * 1000 / 2; - stop_sound(); - state.sample_data_ix = xm_init(&interpreter::state.xm, buf, sample_data, diff --git a/src/interpreter.hpp b/src/interpreter.hpp index 713c467..5c6aa55 100644 --- a/src/interpreter.hpp +++ b/src/interpreter.hpp @@ -24,6 +24,7 @@ struct interpreter_state { int next_line_index; // within the current pattern bool paused; bool reverse; + bool repeat; int deferred_load_tick; int sample_data_ix; @@ -39,6 +40,9 @@ void init(float clock_multiplier); void pause(); void unpause(); +void resume_sound(); +void stop_sound(); + void deferred_load(int buf); void deferred_load_finish(); } diff --git a/src/main.cpp b/src/main.cpp index 6f37842..44f8801 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,8 +24,12 @@ void vbr400() interrupt_exception(); } +static bool inside_interrupt = false; + void vbr600() { + assert(inside_interrupt == false); + inside_interrupt = true; uint32_t sr; asm volatile ("stc sr,%0" : "=r" (sr)); sr |= sh::sr::imask(15); @@ -52,7 +56,7 @@ void vbr600() } else { wait(); aica_sound.common.tactl_tima = aica::tactl_tima::TACTL(0) // increment once every sample - | aica::tactl_tima::TIMA(0xffff) // interrupt after 1 counts + | aica::tactl_tima::TIMA(0xfff0) // interrupt after 4 counts ; } @@ -65,6 +69,7 @@ void vbr600() sr &= ~sh::sr::imask(15); asm volatile ("ldc %0,sr" : : "r" (sr)); + inside_interrupt = false; } #include "memorymap.hpp" @@ -107,7 +112,7 @@ void main() //bool emulator = detect_emulator(); //printf("emulator %d\n", emulator); graphics_init(); - scene::scene_init(scene::id::tracker); + scene::scene_init(scene::id::logo); input::state_init(); cursor::init(); @@ -137,6 +142,14 @@ void main() graphics_event(multi); + int count = 0; + while (next_frame == 0) { + if (count++ > 1000000) { + printf("timeout\n"); + } + }; + next_frame = 0; + scene::transition(); } } diff --git a/src/playlist.cpp b/src/playlist.cpp index 09cf652..d71620b 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -33,23 +33,25 @@ namespace playlist { const int playlist_length = (sizeof (playlist)) / (sizeof (playlist[0])); - void next() + void next(bool stop_sound) { state.playlist_ix += 1; if (state.playlist_ix >= playlist_length) state.playlist_ix = 0; printf("next deferred_load playlist_ix %d\n", state.playlist_ix); + interpreter::stop_sound(); interpreter::deferred_load(playlist[state.playlist_ix].start); } - void prev() + void prev(bool stop_sound) { state.playlist_ix -= 1; if (state.playlist_ix < 0) state.playlist_ix = playlist_length - 1; printf("prev deferred_load playlist_ix %d\n", state.playlist_ix); + interpreter::stop_sound(); interpreter::deferred_load(playlist[state.playlist_ix].start); } } diff --git a/src/playlist.hpp b/src/playlist.hpp index 1b8bf97..3418046 100644 --- a/src/playlist.hpp +++ b/src/playlist.hpp @@ -11,8 +11,8 @@ namespace playlist { int playlist_ix; }; - void next(); - void prev(); + void next(bool stop_sound=true); + void prev(bool stop_sound=true); extern struct state state; extern const playlist_item playlist[]; diff --git a/src/scene/emulator/sound.cpp b/src/scene/emulator/sound.cpp index 7db21d7..1418b80 100644 --- a/src/scene/emulator/sound.cpp +++ b/src/scene/emulator/sound.cpp @@ -10,7 +10,7 @@ namespace scene::emulator::sound { const static void * start = reinterpret_cast(&_binary_pcm_dk_adpcm_start); const static int size = reinterpret_cast(&_binary_pcm_dk_adpcm_size); const static int sample_count = size * 2; - const static int loop_length = 65528; + const static int loop_length = 65520; const static int segment_count = sample_count / loop_length; const static int last_loop = (sample_count % loop_length) & (~0b11); diff --git a/src/scene/logo/sound.cpp b/src/scene/logo/sound.cpp index 37b4e46..5ce5630 100644 --- a/src/scene/logo/sound.cpp +++ b/src/scene/logo/sound.cpp @@ -14,7 +14,7 @@ namespace scene::logo::sound { const static void * start = reinterpret_cast(&_binary_pcm_start3_adpcm_start); const static int size = reinterpret_cast(&_binary_pcm_start3_adpcm_size); const static int sample_count = size * 2; - const static int loop_length = 65528; + const static int loop_length = 65520; const static int segment_count = sample_count / loop_length; const static int last_loop = (sample_count % loop_length) & (~0b11); diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 2e90e38..9e23d06 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -5,6 +5,8 @@ #include "scene/logo/scene.hpp" #include "scene/emulator/scene.hpp" +#include "sh7091/sh7091_bits.hpp" + namespace scene { const scene scenes[] = { [id::tracker] = tracker::scene, @@ -31,7 +33,17 @@ namespace scene { assert(current_scene->done != nullptr); int scene_id = current_scene->done(); if (scene_id >= 0) { + printf("disable interrupt\n"); + uint32_t sr; + asm volatile ("stc sr,%0" : "=r" (sr)); + sr |= sh::sr::imask(15); + asm volatile ("ldc %0,sr" : : "r" (sr)); + scene_init(scene_id); + + printf("enable interrupt\n"); + sr &= ~sh::sr::imask(15); + asm volatile ("ldc %0,sr" : : "r" (sr)); } } } diff --git a/src/scene/tracker/scene.cpp b/src/scene/tracker/scene.cpp index b5377a5..7a6d282 100644 --- a/src/scene/tracker/scene.cpp +++ b/src/scene/tracker/scene.cpp @@ -80,13 +80,21 @@ void fff_click() state.current_tick_rate = state.current_tick_rate / 2; } +void repeat_click() +{ + using namespace interpreter; + printf("repeat\n"); + state.repeat = !state.repeat; +} + #define __length(c) ((sizeof (c)) / (sizeof (c[0]))) widget::button_icon play_button(75, 60, icons::play, play_click); widget::button_icon pause_button(75, 33, icons::pause, pause_click); -widget::button_icon prev_button(79, 30, icons::prev, prev_click); -widget::button_icon next_button(79, 30, icons::next, next_click); +widget::button_icon prev_button(60, 30, icons::prev, prev_click); +widget::button_icon next_button(60, 30, icons::next, next_click); +widget::button_icon repeat_button(37, 30, icons::repeat, repeat_click); widget::button_icon rrr_button(39, 21, icons::rrr, rrr_click); widget::button_icon rr_button(39, 21, icons::rr, rr_click); @@ -102,6 +110,7 @@ int play_pause_length = __length(play_pause_children); widget::widget * prev_next_children[] = { &prev_button, &next_button, + &repeat_button, }; int prev_next_length = __length(prev_next_children); @@ -186,29 +195,51 @@ namespace scene::tracker { transfer_global_polygon_glyph(writer); - float ratio = (float)state.default_tick_rate / (float)state.current_tick_rate; + { + float ratio = (float)state.default_tick_rate / (float)state.current_tick_rate; - float x = 100; - float y = 100; - transfer_string(writer, "speed: . x", - x, y, 1.0 / 10.0, - 0xa7a7a7); - if (state.reverse) - transfer_glyph(writer, '-', - x + glyph::hori_advance * 7, y, 1.0 / 10.0, - 0xffffff); + float x = 100; + float y = 100; + transfer_string(writer, "speed: . x", + x, y, 1.0 / 10.0, + 0xa7a7a7); + if (state.reverse) + transfer_glyph(writer, '-', + x + glyph::hori_advance * 7, y, 1.0 / 10.0, + 0xffffff); - transfer_integer(writer, (int)ratio, - x + glyph::hori_advance * 8, y, 1.0 / 10.0, - 2, ' ', - 0xffffff); + transfer_integer(writer, (int)ratio, + x + glyph::hori_advance * 8, y, 1.0 / 10.0, + 2, ' ', + 0xffffff); - float ratio_fraction = (ratio - ((int)ratio)) * 100; + float ratio_fraction = (ratio - ((int)ratio)) * 100; - transfer_integer(writer, (int)ratio_fraction, - x + glyph::hori_advance * 11, y, 1.0 / 10.0, - 2, '0', - 0xffffff); + transfer_integer(writer, (int)ratio_fraction, + x + glyph::hori_advance * 11, y, 1.0 / 10.0, + 2, '0', + 0xffffff); + } + + { + float x = 100; + float y = 48; + transfer_string(writer, "repeat:", + x, y, 1.0 / 10.0, + 0xa7a7a7); + + x += glyph::hori_advance * (7 + 2); + + if (state.repeat) { + transfer_string(writer, "on", + x, y, 1.0 / 10.0, + 0xffffff); + } else { + transfer_string(writer, "off", + x, y, 1.0 / 10.0, + 0xffffff); + } + } } void transfer(ta_multiwriter& multi)