diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2007-07-16 21:03:25 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2007-07-16 21:03:25 +0000 |
commit | 8552eff9e46ede8968ea13cc172e1c61856bee18 (patch) | |
tree | 7649c84039f0ee4801d56b7b9b38966c3731f79a /apps/codecs/spc | |
parent | 76fa0f7e30398e01d405b4391c30b99dca4c9288 (diff) | |
download | rockbox-8552eff9e46ede8968ea13cc172e1c61856bee18.tar.gz rockbox-8552eff9e46ede8968ea13cc172e1c61856bee18.zip |
Make the SPC codec run like it used to on Coldfire before -Os crushed it. Build as a lib using the old -O option. Should not impact ARM targets.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13919 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/spc')
-rw-r--r-- | apps/codecs/spc/Makefile | 44 | ||||
-rw-r--r-- | apps/codecs/spc/SOURCES | 4 | ||||
-rw-r--r-- | apps/codecs/spc/spc_cpu.c (renamed from apps/codecs/spc/Spc_Cpu.h) | 21 | ||||
-rw-r--r-- | apps/codecs/spc/spc_dsp.c (renamed from apps/codecs/spc/Spc_Dsp.h) | 283 | ||||
-rw-r--r-- | apps/codecs/spc/spc_emu.c | 378 | ||||
-rw-r--r-- | apps/codecs/spc/spc_profiler.c | 64 | ||||
-rw-r--r-- | apps/codecs/spc/spc_profiler.h | 47 |
7 files changed, 586 insertions, 255 deletions
diff --git a/apps/codecs/spc/Makefile b/apps/codecs/spc/Makefile new file mode 100644 index 0000000000..8929149ce2 --- /dev/null +++ b/apps/codecs/spc/Makefile | |||
@@ -0,0 +1,44 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id$ | ||
8 | # | ||
9 | |||
10 | INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ | ||
11 | -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(BUILDDIR) | ||
12 | |||
13 | ifdef APPEXTRA | ||
14 | INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) | ||
15 | endif | ||
16 | |||
17 | SPCOPTS = -O -DROCKBOX | ||
18 | |||
19 | CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET_INC) $(SPCOPTS) $(TARGET) \ | ||
20 | $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} $(PROFILE_OPTS) -DCODEC=1 | ||
21 | |||
22 | # This sets up 'SRC' based on the files mentioned in SOURCES | ||
23 | include $(TOOLSDIR)/makesrc.inc | ||
24 | |||
25 | SOURCES = $(SRC) | ||
26 | OBJS2 := $(SRC:%.c=$(OBJDIR)/%.o) | ||
27 | OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) | ||
28 | DEPFILE = $(OBJDIR)/dep-spc | ||
29 | DIRS = | ||
30 | |||
31 | all: $(OUTPUT) | ||
32 | |||
33 | $(OUTPUT): $(OBJS) | ||
34 | $(call PRINTS,AR+RANLIB $(@F))$(AR) ruv $@ $+ >/dev/null 2>&1 | ||
35 | $(SILENT)$(RANLIB) $@ | ||
36 | |||
37 | include $(TOOLSDIR)/make.inc | ||
38 | |||
39 | clean: | ||
40 | $(call PRINTS,cleaning spc)rm -f $(OBJS) $(OUTPUT) $(DEPFILE) | ||
41 | |||
42 | ifneq ($(MAKECMDGOALS),clean) | ||
43 | -include $(DEPFILE) | ||
44 | endif | ||
diff --git a/apps/codecs/spc/SOURCES b/apps/codecs/spc/SOURCES new file mode 100644 index 0000000000..901232a6eb --- /dev/null +++ b/apps/codecs/spc/SOURCES | |||
@@ -0,0 +1,4 @@ | |||
1 | spc_cpu.c | ||
2 | spc_dsp.c | ||
3 | spc_emu.c | ||
4 | spc_profiler.c | ||
diff --git a/apps/codecs/spc/Spc_Cpu.h b/apps/codecs/spc/spc_cpu.c index b931ca2a3b..3b7c129ad8 100644 --- a/apps/codecs/spc/Spc_Cpu.h +++ b/apps/codecs/spc/spc_cpu.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | ||
8 | * | 9 | * |
9 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) | 10 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) |
10 | * Copyright (C) 2004-2007 Shay Green (blargg) | 11 | * Copyright (C) 2004-2007 Shay Green (blargg) |
@@ -17,9 +18,15 @@ | |||
17 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
18 | * | 19 | * |
19 | ****************************************************************************/ | 20 | ****************************************************************************/ |
20 | 21 | ||
21 | |||
22 | /* The CPU portion (shock!) */ | 22 | /* The CPU portion (shock!) */ |
23 | #include "codec.h" | ||
24 | #include "codecs.h" | ||
25 | #include "spc_codec.h" | ||
26 | #include "spc_profiler.h" | ||
27 | |||
28 | #undef check | ||
29 | #define check assert | ||
23 | 30 | ||
24 | #define READ( addr ) (SPC_read( this, addr, spc_time_ )) | 31 | #define READ( addr ) (SPC_read( this, addr, spc_time_ )) |
25 | #define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ )) | 32 | #define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ )) |
@@ -103,9 +110,7 @@ enum { st_c = 0x01 }; | |||
103 | #define SET_SP( v ) (sp = RAM + 0x101 + (v)) | 110 | #define SET_SP( v ) (sp = RAM + 0x101 + (v)) |
104 | #define GET_SP() (sp - 0x101 - RAM) | 111 | #define GET_SP() (sp - 0x101 - RAM) |
105 | 112 | ||
106 | static long CPU_run( THIS, long start_time ) ICODE_ATTR; | 113 | long CPU_run( THIS, long start_time ) |
107 | |||
108 | static long CPU_run( THIS, long start_time ) | ||
109 | { | 114 | { |
110 | #if 0 | 115 | #if 0 |
111 | ENTER_TIMER(cpu); | 116 | ENTER_TIMER(cpu); |
@@ -1035,3 +1040,9 @@ out_of_time: | |||
1035 | #endif | 1040 | #endif |
1036 | return spc_time_; | 1041 | return spc_time_; |
1037 | } | 1042 | } |
1043 | |||
1044 | void CPU_Init( THIS ) | ||
1045 | { | ||
1046 | ci->memcpy( this->cycle_table, cycle_table, sizeof cycle_table ); | ||
1047 | } | ||
1048 | |||
diff --git a/apps/codecs/spc/Spc_Dsp.h b/apps/codecs/spc/spc_dsp.c index d670b20c52..6a8aaebc7f 100644 --- a/apps/codecs/spc/Spc_Dsp.h +++ b/apps/codecs/spc/spc_dsp.c | |||
@@ -20,196 +20,24 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | /* The DSP portion (awe!) */ | 22 | /* The DSP portion (awe!) */ |
23 | #include "codec.h" | ||
24 | #include "codecs.h" | ||
25 | #include "spc_codec.h" | ||
26 | #include "spc_profiler.h" | ||
23 | 27 | ||
24 | enum { voice_count = 8 }; | 28 | #ifdef CPU_COLDFIRE |
25 | enum { register_count = 128 }; | 29 | static int32_t fir_buf[FIR_BUF_HALF] |
26 | 30 | __attribute__ ((aligned (FIR_BUF_SIZE*2))) IBSS_ATTR; | |
27 | struct raw_voice_t | ||
28 | { | ||
29 | int8_t volume [2]; | ||
30 | uint8_t rate [2]; | ||
31 | uint8_t waveform; | ||
32 | uint8_t adsr [2]; /* envelope rates for attack, decay, and sustain */ | ||
33 | uint8_t gain; /* envelope gain (if not using ADSR) */ | ||
34 | int8_t envx; /* current envelope level */ | ||
35 | int8_t outx; /* current sample */ | ||
36 | int8_t unused [6]; | ||
37 | }; | ||
38 | |||
39 | struct globals_t | ||
40 | { | ||
41 | int8_t unused1 [12]; | ||
42 | int8_t volume_0; /* 0C Main Volume Left (-.7) */ | ||
43 | int8_t echo_feedback; /* 0D Echo Feedback (-.7) */ | ||
44 | int8_t unused2 [14]; | ||
45 | int8_t volume_1; /* 1C Main Volume Right (-.7) */ | ||
46 | int8_t unused3 [15]; | ||
47 | int8_t echo_volume_0; /* 2C Echo Volume Left (-.7) */ | ||
48 | uint8_t pitch_mods; /* 2D Pitch Modulation on/off for each voice */ | ||
49 | int8_t unused4 [14]; | ||
50 | int8_t echo_volume_1; /* 3C Echo Volume Right (-.7) */ | ||
51 | uint8_t noise_enables; /* 3D Noise output on/off for each voice */ | ||
52 | int8_t unused5 [14]; | ||
53 | uint8_t key_ons; /* 4C Key On for each voice */ | ||
54 | uint8_t echo_ons; /* 4D Echo on/off for each voice */ | ||
55 | int8_t unused6 [14]; | ||
56 | uint8_t key_offs; /* 5C key off for each voice | ||
57 | (instantiates release mode) */ | ||
58 | uint8_t wave_page; /* 5D source directory (wave table offsets) */ | ||
59 | int8_t unused7 [14]; | ||
60 | uint8_t flags; /* 6C flags and noise freq */ | ||
61 | uint8_t echo_page; /* 6D */ | ||
62 | int8_t unused8 [14]; | ||
63 | uint8_t wave_ended; /* 7C */ | ||
64 | uint8_t echo_delay; /* 7D ms >> 4 */ | ||
65 | char unused9 [2]; | ||
66 | }; | ||
67 | |||
68 | enum state_t { /* -1, 0, +1 allows more efficient if statements */ | ||
69 | state_decay = -1, | ||
70 | state_sustain = 0, | ||
71 | state_attack = +1, | ||
72 | state_release = 2 | ||
73 | }; | ||
74 | |||
75 | struct cache_entry_t | ||
76 | { | ||
77 | int16_t const* samples; | ||
78 | unsigned end; /* past-the-end position */ | ||
79 | unsigned loop; /* number of samples in loop */ | ||
80 | unsigned start_addr; | ||
81 | }; | ||
82 | |||
83 | enum { brr_block_size = 16 }; | ||
84 | |||
85 | struct voice_t | ||
86 | { | ||
87 | #if SPC_BRRCACHE | ||
88 | int16_t const* samples; | ||
89 | long wave_end; | ||
90 | int wave_loop; | ||
91 | #else | ||
92 | int16_t samples [3 + brr_block_size + 1]; | ||
93 | int block_header; /* header byte from current block */ | ||
94 | #endif | 31 | #endif |
95 | uint8_t const* addr; | ||
96 | short volume [2]; | ||
97 | long position;/* position in samples buffer, with 12-bit fraction */ | ||
98 | short envx; | ||
99 | short env_mode; | ||
100 | short env_timer; | ||
101 | short key_on_delay; | ||
102 | }; | ||
103 | 32 | ||
104 | #if SPC_BRRCACHE | 33 | #if SPC_BRRCACHE |
105 | /* a little extra for samples that go past end */ | 34 | /* a little extra for samples that go past end */ |
106 | static int16_t BRRcache [0x20000 + 32]; | 35 | int16_t BRRcache [0x20000 + 32]; |
107 | #endif | ||
108 | |||
109 | enum { fir_buf_half = 8 }; | ||
110 | |||
111 | #ifdef CPU_COLDFIRE | ||
112 | /* global because of the large aligment requirement for hardware masking - | ||
113 | * L-R interleaved 16-bit samples for easy loading and mac.w use. | ||
114 | */ | ||
115 | enum | ||
116 | { | ||
117 | fir_buf_size = fir_buf_half * sizeof ( int32_t ), | ||
118 | fir_buf_mask = ~fir_buf_size | ||
119 | }; | ||
120 | int32_t fir_buf[fir_buf_half] | ||
121 | __attribute__ ((aligned (fir_buf_size*2))) IBSS_ATTR; | ||
122 | #endif /* CPU_COLDFIRE */ | ||
123 | |||
124 | struct Spc_Dsp | ||
125 | { | ||
126 | union | ||
127 | { | ||
128 | struct raw_voice_t voice [voice_count]; | ||
129 | uint8_t reg [register_count]; | ||
130 | struct globals_t g; | ||
131 | int16_t align; | ||
132 | } r; | ||
133 | |||
134 | unsigned echo_pos; | ||
135 | int keys_down; | ||
136 | int noise_count; | ||
137 | uint16_t noise; /* also read as int16_t */ | ||
138 | |||
139 | #ifdef CPU_COLDFIRE | ||
140 | /* circularly hardware masked address */ | ||
141 | int32_t *fir_ptr; | ||
142 | /* wrapped address just behind current position - | ||
143 | allows mac.w to increment and mask fir_ptr */ | ||
144 | int32_t *last_fir_ptr; | ||
145 | /* copy of echo FIR constants as int16_t for use with mac.w */ | ||
146 | int16_t fir_coeff[voice_count]; | ||
147 | #else | ||
148 | /* fir_buf [i + 8] == fir_buf [i], to avoid wrap checking in FIR code */ | ||
149 | int fir_pos; /* (0 to 7) */ | ||
150 | int fir_buf [fir_buf_half * 2] [2]; | ||
151 | /* copy of echo FIR constants as int, for faster access */ | ||
152 | int fir_coeff [voice_count]; | ||
153 | #endif | ||
154 | |||
155 | struct voice_t voice_state [voice_count]; | ||
156 | |||
157 | #if SPC_BRRCACHE | ||
158 | uint8_t oldsize; | ||
159 | struct cache_entry_t wave_entry [256]; | ||
160 | struct cache_entry_t wave_entry_old [256]; | ||
161 | #endif | ||
162 | }; | ||
163 | |||
164 | struct src_dir | ||
165 | { | ||
166 | char start [2]; | ||
167 | char loop [2]; | ||
168 | }; | ||
169 | |||
170 | static void DSP_reset( struct Spc_Dsp* this ) | ||
171 | { | ||
172 | this->keys_down = 0; | ||
173 | this->echo_pos = 0; | ||
174 | this->noise_count = 0; | ||
175 | this->noise = 2; | ||
176 | |||
177 | this->r.g.flags = 0xE0; /* reset, mute, echo off */ | ||
178 | this->r.g.key_ons = 0; | ||
179 | |||
180 | memset( this->voice_state, 0, sizeof this->voice_state ); | ||
181 | |||
182 | int i; | ||
183 | for ( i = voice_count; --i >= 0; ) | ||
184 | { | ||
185 | struct voice_t* v = this->voice_state + i; | ||
186 | v->env_mode = state_release; | ||
187 | v->addr = ram.ram; | ||
188 | } | ||
189 | |||
190 | #if SPC_BRRCACHE | ||
191 | this->oldsize = 0; | ||
192 | for ( i = 0; i < 256; i++ ) | ||
193 | this->wave_entry [i].start_addr = -1; | ||
194 | #endif | ||
195 | |||
196 | #ifdef CPU_COLDFIRE | ||
197 | this->fir_ptr = fir_buf; | ||
198 | this->last_fir_ptr = &fir_buf [7]; | ||
199 | memset( fir_buf, 0, sizeof fir_buf ); | ||
200 | #else | ||
201 | this->fir_pos = 0; | ||
202 | memset( this->fir_buf, 0, sizeof this->fir_buf ); | ||
203 | #endif | 36 | #endif |
204 | 37 | ||
205 | assert( offsetof (struct globals_t,unused9 [2]) == register_count ); | 38 | void DSP_write( struct Spc_Dsp* this, int i, int data ) |
206 | assert( sizeof (this->r.voice) == register_count ); | ||
207 | } | ||
208 | |||
209 | static void DSP_write( struct Spc_Dsp* this, int i, int data ) ICODE_ATTR; | ||
210 | static void DSP_write( struct Spc_Dsp* this, int i, int data ) | ||
211 | { | 39 | { |
212 | assert( (unsigned) i < register_count ); | 40 | assert( (unsigned) i < REGISTER_COUNT ); |
213 | 41 | ||
214 | this->r.reg [i] = data; | 42 | this->r.reg [i] = data; |
215 | int high = i >> 4; | 43 | int high = i >> 4; |
@@ -228,12 +56,6 @@ static void DSP_write( struct Spc_Dsp* this, int i, int data ) | |||
228 | } | 56 | } |
229 | } | 57 | } |
230 | 58 | ||
231 | static inline int DSP_read( struct Spc_Dsp* this, int i ) | ||
232 | { | ||
233 | assert( (unsigned) i < register_count ); | ||
234 | return this->r.reg [i]; | ||
235 | } | ||
236 | |||
237 | /* if ( n < -32768 ) out = -32768; */ | 59 | /* if ( n < -32768 ) out = -32768; */ |
238 | /* if ( n > 32767 ) out = 32767; */ | 60 | /* if ( n > 32767 ) out = 32767; */ |
239 | #define CLAMP16( n, out )\ | 61 | #define CLAMP16( n, out )\ |
@@ -321,8 +143,8 @@ static void decode_brr( struct Spc_Dsp* this, unsigned start_addr, | |||
321 | int const left_shift = left_shifts [scale]; | 143 | int const left_shift = left_shifts [scale]; |
322 | 144 | ||
323 | /* output position */ | 145 | /* output position */ |
324 | out += brr_block_size; | 146 | out += BRR_BLOCK_SIZE; |
325 | int offset = -brr_block_size << 2; | 147 | int offset = -BRR_BLOCK_SIZE << 2; |
326 | 148 | ||
327 | do /* decode and filter 16 samples */ | 149 | do /* decode and filter 16 samples */ |
328 | { | 150 | { |
@@ -432,10 +254,10 @@ static void key_on(struct Spc_Dsp* const this, struct voice_t* const voice, | |||
432 | { | 254 | { |
433 | voice->addr = RAM + start_addr; | 255 | voice->addr = RAM + start_addr; |
434 | /* BRR filter uses previous samples */ | 256 | /* BRR filter uses previous samples */ |
435 | voice->samples [brr_block_size + 1] = 0; | 257 | voice->samples [BRR_BLOCK_SIZE + 1] = 0; |
436 | voice->samples [brr_block_size + 2] = 0; | 258 | voice->samples [BRR_BLOCK_SIZE + 2] = 0; |
437 | /* decode three samples immediately */ | 259 | /* decode three samples immediately */ |
438 | voice->position = (brr_block_size + 3) * 0x1000 - 1; | 260 | voice->position = (BRR_BLOCK_SIZE + 3) * 0x1000 - 1; |
439 | voice->block_header = 0; /* "previous" BRR header */ | 261 | voice->block_header = 0; /* "previous" BRR header */ |
440 | } | 262 | } |
441 | #else | 263 | #else |
@@ -460,9 +282,7 @@ static void key_on(struct Spc_Dsp* const this, struct voice_t* const voice, | |||
460 | } | 282 | } |
461 | } | 283 | } |
462 | 284 | ||
463 | static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | 285 | void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) |
464 | ICODE_ATTR; | ||
465 | static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | ||
466 | { | 286 | { |
467 | #undef RAM | 287 | #undef RAM |
468 | #ifdef CPU_ARM | 288 | #ifdef CPU_ARM |
@@ -516,7 +336,7 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
516 | #ifdef ROCKBOX_BIG_ENDIAN | 336 | #ifdef ROCKBOX_BIG_ENDIAN |
517 | /* Convert endiannesses before entering loops - these | 337 | /* Convert endiannesses before entering loops - these |
518 | get used alot */ | 338 | get used alot */ |
519 | const uint32_t rates[voice_count] = | 339 | const uint32_t rates[VOICE_COUNT] = |
520 | { | 340 | { |
521 | GET_LE16A( this->r.voice[0].rate ) & 0x3FFF, | 341 | GET_LE16A( this->r.voice[0].rate ) & 0x3FFF, |
522 | GET_LE16A( this->r.voice[1].rate ) & 0x3FFF, | 342 | GET_LE16A( this->r.voice[1].rate ) & 0x3FFF, |
@@ -531,7 +351,7 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
531 | #define IF_RBE(...) __VA_ARGS__ | 351 | #define IF_RBE(...) __VA_ARGS__ |
532 | #ifdef CPU_COLDFIRE | 352 | #ifdef CPU_COLDFIRE |
533 | /* Initialize mask register with the buffer address mask */ | 353 | /* Initialize mask register with the buffer address mask */ |
534 | asm volatile ("move.l %[m], %%mask" : : [m]"i"(fir_buf_mask)); | 354 | asm volatile ("move.l %[m], %%mask" : : [m]"i"(FIR_BUF_MASK)); |
535 | const int echo_wrap = (this->r.g.echo_delay & 15) * 0x800; | 355 | const int echo_wrap = (this->r.g.echo_delay & 15) * 0x800; |
536 | const int echo_start = this->r.g.echo_page * 0x100; | 356 | const int echo_start = this->r.g.echo_page * 0x100; |
537 | #endif /* CPU_COLDFIRE */ | 357 | #endif /* CPU_COLDFIRE */ |
@@ -757,9 +577,9 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
757 | #endif | 577 | #endif |
758 | #if !SPC_BRRCACHE | 578 | #if !SPC_BRRCACHE |
759 | /* Decode BRR block */ | 579 | /* Decode BRR block */ |
760 | if ( voice->position >= brr_block_size * 0x1000 ) | 580 | if ( voice->position >= BRR_BLOCK_SIZE * 0x1000 ) |
761 | { | 581 | { |
762 | voice->position -= brr_block_size * 0x1000; | 582 | voice->position -= BRR_BLOCK_SIZE * 0x1000; |
763 | 583 | ||
764 | uint8_t const* addr = voice->addr; | 584 | uint8_t const* addr = voice->addr; |
765 | if ( addr >= RAM + 0x10000 ) | 585 | if ( addr >= RAM + 0x10000 ) |
@@ -805,13 +625,13 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
805 | int const left_shift = left_shifts [scale]; | 625 | int const left_shift = left_shifts [scale]; |
806 | 626 | ||
807 | /* previous samples */ | 627 | /* previous samples */ |
808 | int smp2 = voice->samples [brr_block_size + 1]; | 628 | int smp2 = voice->samples [BRR_BLOCK_SIZE + 1]; |
809 | int smp1 = voice->samples [brr_block_size + 2]; | 629 | int smp1 = voice->samples [BRR_BLOCK_SIZE + 2]; |
810 | voice->samples [0] = voice->samples [brr_block_size]; | 630 | voice->samples [0] = voice->samples [BRR_BLOCK_SIZE]; |
811 | 631 | ||
812 | /* output position */ | 632 | /* output position */ |
813 | short* out = voice->samples + (1 + brr_block_size); | 633 | short* out = voice->samples + (1 + BRR_BLOCK_SIZE); |
814 | int offset = -brr_block_size << 2; | 634 | int offset = -BRR_BLOCK_SIZE << 2; |
815 | 635 | ||
816 | /* if next block has end flag set, | 636 | /* if next block has end flag set, |
817 | this block ends early (verified) */ | 637 | this block ends early (verified) */ |
@@ -820,9 +640,9 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
820 | /* arrange for last 9 samples to be skipped */ | 640 | /* arrange for last 9 samples to be skipped */ |
821 | int const skip = 9; | 641 | int const skip = 9; |
822 | out += (skip & 1); | 642 | out += (skip & 1); |
823 | voice->samples [skip] = voice->samples [brr_block_size]; | 643 | voice->samples [skip] = voice->samples [BRR_BLOCK_SIZE]; |
824 | voice->position += skip * 0x1000; | 644 | voice->position += skip * 0x1000; |
825 | offset = (-brr_block_size + (skip & ~1)) << 2; | 645 | offset = (-BRR_BLOCK_SIZE + (skip & ~1)) << 2; |
826 | addr -= skip / 2; | 646 | addr -= skip / 2; |
827 | /* force sample to end on next decode */ | 647 | /* force sample to end on next decode */ |
828 | voice->block_header = 1; | 648 | voice->block_header = 1; |
@@ -1026,7 +846,7 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
1026 | "asr.l %[sh], %[output] \r\n" | 846 | "asr.l %[sh], %[output] \r\n" |
1027 | "mac.l %[vvol_0], %[output], %%acc0 \r\n" | 847 | "mac.l %[vvol_0], %[output], %%acc0 \r\n" |
1028 | "mac.l %[vvol_1], %[output], %%acc1 \r\n" | 848 | "mac.l %[vvol_1], %[output], %%acc1 \r\n" |
1029 | : [output]"=&r"(amp_0) | 849 | : [output]"=&d"(amp_0) |
1030 | : [vvol_0]"r"((int)voice->volume[0]), | 850 | : [vvol_0]"r"((int)voice->volume[0]), |
1031 | [vvol_1]"r"((int)voice->volume[1]), | 851 | [vvol_1]"r"((int)voice->volume[1]), |
1032 | [sh]"d"(11) | 852 | [sh]"d"(11) |
@@ -1252,12 +1072,12 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
1252 | 1072 | ||
1253 | /* Keep last 8 samples */ | 1073 | /* Keep last 8 samples */ |
1254 | int (* const fir_ptr) [2] = this->fir_buf + this->fir_pos; | 1074 | int (* const fir_ptr) [2] = this->fir_buf + this->fir_pos; |
1255 | this->fir_pos = (this->fir_pos + 1) & (fir_buf_half - 1); | 1075 | this->fir_pos = (this->fir_pos + 1) & (FIR_BUF_HALF - 1); |
1256 | fir_ptr [ 0] [0] = fb_0; | 1076 | fir_ptr [ 0] [0] = fb_0; |
1257 | fir_ptr [ 0] [1] = fb_1; | 1077 | fir_ptr [ 0] [1] = fb_1; |
1258 | /* duplicate at +8 eliminates wrap checking below */ | 1078 | /* duplicate at +8 eliminates wrap checking below */ |
1259 | fir_ptr [fir_buf_half] [0] = fb_0; | 1079 | fir_ptr [FIR_BUF_HALF] [0] = fb_0; |
1260 | fir_ptr [fir_buf_half] [1] = fb_1; | 1080 | fir_ptr [FIR_BUF_HALF] [1] = fb_1; |
1261 | 1081 | ||
1262 | /* Apply FIR */ | 1082 | /* Apply FIR */ |
1263 | fb_0 *= this->fir_coeff [0]; | 1083 | fb_0 *= this->fir_coeff [0]; |
@@ -1311,12 +1131,41 @@ static void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
1311 | #endif | 1131 | #endif |
1312 | } | 1132 | } |
1313 | 1133 | ||
1314 | static inline void DSP_run( struct Spc_Dsp* this, long count, int32_t* out ) | 1134 | void DSP_reset( struct Spc_Dsp* this ) |
1315 | { | 1135 | { |
1316 | /* Should we just fill the buffer with silence? Flags won't be cleared */ | 1136 | this->keys_down = 0; |
1317 | /* during this run so it seems it should keep resetting every sample. */ | 1137 | this->echo_pos = 0; |
1318 | if ( this->r.g.flags & 0x80 ) | 1138 | this->noise_count = 0; |
1319 | DSP_reset( this ); | 1139 | this->noise = 2; |
1320 | 1140 | ||
1321 | DSP_run_( this, count, out ); | 1141 | this->r.g.flags = 0xE0; /* reset, mute, echo off */ |
1142 | this->r.g.key_ons = 0; | ||
1143 | |||
1144 | ci->memset( this->voice_state, 0, sizeof this->voice_state ); | ||
1145 | |||
1146 | int i; | ||
1147 | for ( i = VOICE_COUNT; --i >= 0; ) | ||
1148 | { | ||
1149 | struct voice_t* v = this->voice_state + i; | ||
1150 | v->env_mode = state_release; | ||
1151 | v->addr = ram.ram; | ||
1152 | } | ||
1153 | |||
1154 | #if SPC_BRRCACHE | ||
1155 | this->oldsize = 0; | ||
1156 | for ( i = 0; i < 256; i++ ) | ||
1157 | this->wave_entry [i].start_addr = -1; | ||
1158 | #endif | ||
1159 | |||
1160 | #ifdef CPU_COLDFIRE | ||
1161 | this->fir_ptr = fir_buf; | ||
1162 | this->last_fir_ptr = &fir_buf [7]; | ||
1163 | ci->memset( fir_buf, 0, sizeof fir_buf ); | ||
1164 | #else | ||
1165 | this->fir_pos = 0; | ||
1166 | ci->memset( this->fir_buf, 0, sizeof this->fir_buf ); | ||
1167 | #endif | ||
1168 | |||
1169 | assert( offsetof (struct globals_t,unused9 [2]) == REGISTER_COUNT ); | ||
1170 | assert( sizeof (this->r.voice) == REGISTER_COUNT ); | ||
1322 | } | 1171 | } |
diff --git a/apps/codecs/spc/spc_emu.c b/apps/codecs/spc/spc_emu.c new file mode 100644 index 0000000000..30aaf5d64b --- /dev/null +++ b/apps/codecs/spc/spc_emu.c | |||
@@ -0,0 +1,378 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) | ||
11 | * Copyright (C) 2004-2007 Shay Green (blargg) | ||
12 | * Copyright (C) 2002 Brad Martin | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "codec.h" | ||
22 | #include "codecs.h" | ||
23 | #include "spc_codec.h" | ||
24 | #include "spc_profiler.h" | ||
25 | |||
26 | /* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */ | ||
27 | /* DSP Based on Brad Martin's OpenSPC DSP emulator */ | ||
28 | /* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */ | ||
29 | |||
30 | struct cpu_ram_t ram; | ||
31 | |||
32 | /**************** Timers ****************/ | ||
33 | |||
34 | void Timer_run_( struct Timer* t, long time ) | ||
35 | { | ||
36 | /* when disabled, next_tick should always be in the future */ | ||
37 | assert( t->enabled ); | ||
38 | |||
39 | int elapsed = ((time - t->next_tick) >> t->shift) + 1; | ||
40 | t->next_tick += elapsed << t->shift; | ||
41 | |||
42 | elapsed += t->count; | ||
43 | if ( elapsed >= t->period ) /* avoid unnecessary division */ | ||
44 | { | ||
45 | int n = elapsed / t->period; | ||
46 | elapsed -= n * t->period; | ||
47 | t->counter = (t->counter + n) & 15; | ||
48 | } | ||
49 | t->count = elapsed; | ||
50 | } | ||
51 | |||
52 | /**************** SPC emulator ****************/ | ||
53 | /* 1.024 MHz clock / 32000 samples per second */ | ||
54 | |||
55 | static void SPC_enable_rom( THIS, int enable ) | ||
56 | { | ||
57 | if ( this->rom_enabled != enable ) | ||
58 | { | ||
59 | this->rom_enabled = enable; | ||
60 | ci->memcpy( RAM + ROM_ADDR, (enable ? this->boot_rom : this->extra_ram), ROM_SIZE ); | ||
61 | /* TODO: ROM can still get overwritten when DSP writes to echo buffer */ | ||
62 | } | ||
63 | } | ||
64 | |||
65 | void SPC_Init( THIS ) | ||
66 | { | ||
67 | this->timer [0].shift = 4 + 3; /* 8 kHz */ | ||
68 | this->timer [1].shift = 4 + 3; /* 8 kHz */ | ||
69 | this->timer [2].shift = 4; /* 8 kHz */ | ||
70 | |||
71 | /* Put STOP instruction around memory to catch PC underflow/overflow. */ | ||
72 | ci->memset( ram.padding1, 0xFF, sizeof ram.padding1 ); | ||
73 | ci->memset( ram.padding2, 0xFF, sizeof ram.padding2 ); | ||
74 | |||
75 | /* A few tracks read from the last four bytes of IPL ROM */ | ||
76 | this->boot_rom [sizeof this->boot_rom - 2] = 0xC0; | ||
77 | this->boot_rom [sizeof this->boot_rom - 1] = 0xFF; | ||
78 | ci->memset( this->boot_rom, 0, sizeof this->boot_rom - 2 ); | ||
79 | } | ||
80 | |||
81 | static void SPC_load_state( THIS, struct cpu_regs_t const* cpu_state, | ||
82 | const void* new_ram, const void* dsp_state ) | ||
83 | { | ||
84 | ci->memcpy(&(this->r),cpu_state,sizeof this->r); | ||
85 | |||
86 | /* ram */ | ||
87 | ci->memcpy( RAM, new_ram, sizeof RAM ); | ||
88 | ci->memcpy( this->extra_ram, RAM + ROM_ADDR, sizeof this->extra_ram ); | ||
89 | |||
90 | /* boot rom (have to force enable_rom() to update it) */ | ||
91 | this->rom_enabled = !(RAM [0xF1] & 0x80); | ||
92 | SPC_enable_rom( this, !this->rom_enabled ); | ||
93 | |||
94 | /* dsp */ | ||
95 | /* some SPCs rely on DSP immediately generating one sample */ | ||
96 | this->extra_cycles = 32; | ||
97 | DSP_reset( &this->dsp ); | ||
98 | int i; | ||
99 | for ( i = 0; i < REGISTER_COUNT; i++ ) | ||
100 | DSP_write( &this->dsp, i, ((uint8_t const*) dsp_state) [i] ); | ||
101 | |||
102 | /* timers */ | ||
103 | for ( i = 0; i < TIMER_COUNT; i++ ) | ||
104 | { | ||
105 | struct Timer* t = &this->timer [i]; | ||
106 | |||
107 | t->next_tick = -EXTRA_CLOCKS; | ||
108 | t->enabled = (RAM [0xF1] >> i) & 1; | ||
109 | if ( !t->enabled ) | ||
110 | t->next_tick = TIMER_DISABLED_TIME; | ||
111 | t->count = 0; | ||
112 | t->counter = RAM [0xFD + i] & 15; | ||
113 | |||
114 | int p = RAM [0xFA + i]; | ||
115 | if ( !p ) | ||
116 | p = 0x100; | ||
117 | t->period = p; | ||
118 | } | ||
119 | |||
120 | /* Handle registers which already give 0 when read by | ||
121 | setting RAM and not changing it. | ||
122 | Put STOP instruction in registers which can be read, | ||
123 | to catch attempted execution. */ | ||
124 | RAM [0xF0] = 0; | ||
125 | RAM [0xF1] = 0; | ||
126 | RAM [0xF3] = 0xFF; | ||
127 | RAM [0xFA] = 0; | ||
128 | RAM [0xFB] = 0; | ||
129 | RAM [0xFC] = 0; | ||
130 | RAM [0xFD] = 0xFF; | ||
131 | RAM [0xFE] = 0xFF; | ||
132 | RAM [0xFF] = 0xFF; | ||
133 | } | ||
134 | |||
135 | static void clear_echo( THIS ) | ||
136 | { | ||
137 | if ( !(DSP_read( &this->dsp, 0x6C ) & 0x20) ) | ||
138 | { | ||
139 | unsigned addr = 0x100 * DSP_read( &this->dsp, 0x6D ); | ||
140 | size_t size = 0x800 * DSP_read( &this->dsp, 0x7D ); | ||
141 | size_t max_size = sizeof RAM - addr; | ||
142 | if ( size > max_size ) | ||
143 | size = sizeof RAM - addr; | ||
144 | ci->memset( RAM + addr, 0xFF, size ); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | int SPC_load_spc( THIS, const void* data, long size ) | ||
149 | { | ||
150 | struct spc_file_t const* spc = (struct spc_file_t const*) data; | ||
151 | struct cpu_regs_t regs; | ||
152 | |||
153 | if ( size < SPC_FILE_SIZE ) | ||
154 | return -1; | ||
155 | |||
156 | if ( ci->memcmp( spc->signature, "SNES-SPC700 Sound File Data", 27 ) != 0 ) | ||
157 | return -1; | ||
158 | |||
159 | regs.pc = spc->pc [1] * 0x100 + spc->pc [0]; | ||
160 | regs.a = spc->a; | ||
161 | regs.x = spc->x; | ||
162 | regs.y = spc->y; | ||
163 | regs.status = spc->status; | ||
164 | regs.sp = spc->sp; | ||
165 | |||
166 | if ( (unsigned long) size >= sizeof *spc ) | ||
167 | ci->memcpy( this->boot_rom, spc->ipl_rom, sizeof this->boot_rom ); | ||
168 | |||
169 | SPC_load_state( this, ®s, spc->ram, spc->dsp ); | ||
170 | |||
171 | clear_echo(this); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /**************** DSP interaction ****************/ | ||
177 | void SPC_run_dsp_( THIS, long time ) | ||
178 | { | ||
179 | /* divide by CLOCKS_PER_SAMPLE */ | ||
180 | int count = ((time - this->next_dsp) >> 5) + 1; | ||
181 | int32_t* buf = this->sample_buf; | ||
182 | this->sample_buf = buf + count; | ||
183 | this->next_dsp += count * CLOCKS_PER_SAMPLE; | ||
184 | DSP_run( &this->dsp, count, buf ); | ||
185 | } | ||
186 | |||
187 | int SPC_read( THIS, unsigned addr, long const time ) | ||
188 | { | ||
189 | int result = RAM [addr]; | ||
190 | |||
191 | if ( ((unsigned) (addr - 0xF0)) < 0x10 ) | ||
192 | { | ||
193 | assert( 0xF0 <= addr && addr <= 0xFF ); | ||
194 | |||
195 | /* counters */ | ||
196 | int i = addr - 0xFD; | ||
197 | if ( i >= 0 ) | ||
198 | { | ||
199 | struct Timer* t = &this->timer [i]; | ||
200 | Timer_run( t, time ); | ||
201 | result = t->counter; | ||
202 | t->counter = 0; | ||
203 | } | ||
204 | /* dsp */ | ||
205 | else if ( addr == 0xF3 ) | ||
206 | { | ||
207 | SPC_run_dsp( this, time ); | ||
208 | result = DSP_read( &this->dsp, RAM [0xF2] & 0x7F ); | ||
209 | } | ||
210 | } | ||
211 | return result; | ||
212 | } | ||
213 | |||
214 | void SPC_write( THIS, unsigned addr, int data, long const time ) | ||
215 | { | ||
216 | /* first page is very common */ | ||
217 | if ( addr < 0xF0 ) | ||
218 | { | ||
219 | RAM [addr] = (uint8_t) data; | ||
220 | } | ||
221 | else switch ( addr ) | ||
222 | { | ||
223 | /* RAM */ | ||
224 | default: | ||
225 | if ( addr < ROM_ADDR ) | ||
226 | { | ||
227 | RAM [addr] = (uint8_t) data; | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | this->extra_ram [addr - ROM_ADDR] = (uint8_t) data; | ||
232 | if ( !this->rom_enabled ) | ||
233 | RAM [addr] = (uint8_t) data; | ||
234 | } | ||
235 | break; | ||
236 | |||
237 | /* DSP */ | ||
238 | /*case 0xF2:*/ /* mapped to RAM */ | ||
239 | case 0xF3: { | ||
240 | SPC_run_dsp( this, time ); | ||
241 | int reg = RAM [0xF2]; | ||
242 | if ( reg < REGISTER_COUNT ) { | ||
243 | DSP_write( &this->dsp, reg, data ); | ||
244 | } | ||
245 | else { | ||
246 | /*dprintf( "DSP write to $%02X\n", (int) reg ); */ | ||
247 | } | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | case 0xF0: /* Test register */ | ||
252 | /*dprintf( "Wrote $%02X to $F0\n", (int) data ); */ | ||
253 | break; | ||
254 | |||
255 | /* Config */ | ||
256 | case 0xF1: | ||
257 | { | ||
258 | int i; | ||
259 | /* timers */ | ||
260 | for ( i = 0; i < TIMER_COUNT; i++ ) | ||
261 | { | ||
262 | struct Timer * t = this->timer+i; | ||
263 | if ( !(data & (1 << i)) ) | ||
264 | { | ||
265 | t->enabled = 0; | ||
266 | t->next_tick = TIMER_DISABLED_TIME; | ||
267 | } | ||
268 | else if ( !t->enabled ) | ||
269 | { | ||
270 | /* just enabled */ | ||
271 | t->enabled = 1; | ||
272 | t->counter = 0; | ||
273 | t->count = 0; | ||
274 | t->next_tick = time; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* port clears */ | ||
279 | if ( data & 0x10 ) | ||
280 | { | ||
281 | RAM [0xF4] = 0; | ||
282 | RAM [0xF5] = 0; | ||
283 | } | ||
284 | if ( data & 0x20 ) | ||
285 | { | ||
286 | RAM [0xF6] = 0; | ||
287 | RAM [0xF7] = 0; | ||
288 | } | ||
289 | |||
290 | SPC_enable_rom( this, (data & 0x80) != 0 ); | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | /* Ports */ | ||
295 | case 0xF4: | ||
296 | case 0xF5: | ||
297 | case 0xF6: | ||
298 | case 0xF7: | ||
299 | /* to do: handle output ports */ | ||
300 | break; | ||
301 | |||
302 | /* verified on SNES that these are read/write (RAM) */ | ||
303 | /*case 0xF8: */ | ||
304 | /*case 0xF9: */ | ||
305 | |||
306 | /* Timers */ | ||
307 | case 0xFA: | ||
308 | case 0xFB: | ||
309 | case 0xFC: { | ||
310 | int i = addr - 0xFA; | ||
311 | struct Timer* t = &this->timer [i]; | ||
312 | if ( (t->period & 0xFF) != data ) | ||
313 | { | ||
314 | Timer_run( t, time ); | ||
315 | this->timer[i].period = data ? data : 0x100; | ||
316 | } | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | /* Counters (cleared on write) */ | ||
321 | case 0xFD: | ||
322 | case 0xFE: | ||
323 | case 0xFF: | ||
324 | /*dprintf( "Wrote to counter $%02X\n", (int) addr ); */ | ||
325 | this->timer [addr - 0xFD].counter = 0; | ||
326 | break; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | /**************** Sample generation ****************/ | ||
331 | int SPC_play( THIS, long count, int32_t* out ) | ||
332 | { | ||
333 | int i; | ||
334 | assert( count % 2 == 0 ); /* output is always in pairs of samples */ | ||
335 | |||
336 | long start_time = -(count >> 1) * CLOCKS_PER_SAMPLE - EXTRA_CLOCKS; | ||
337 | |||
338 | /* DSP output is made on-the-fly when DSP registers are read or written */ | ||
339 | this->sample_buf = out; | ||
340 | this->next_dsp = start_time + CLOCKS_PER_SAMPLE; | ||
341 | |||
342 | /* Localize timer next_tick times and run them to the present to prevent | ||
343 | a running but ignored timer's next_tick from getting too far behind | ||
344 | and overflowing. */ | ||
345 | for ( i = 0; i < TIMER_COUNT; i++ ) | ||
346 | { | ||
347 | struct Timer* t = &this->timer [i]; | ||
348 | if ( t->enabled ) | ||
349 | { | ||
350 | t->next_tick += start_time + EXTRA_CLOCKS; | ||
351 | Timer_run( t, start_time ); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /* Run from start_time to 0, pre-advancing by extra cycles from last run */ | ||
356 | this->extra_cycles = CPU_run( this, start_time + this->extra_cycles ) + | ||
357 | EXTRA_CLOCKS; | ||
358 | if ( this->extra_cycles < 0 ) | ||
359 | { | ||
360 | /*dprintf( "Unhandled instruction $%02X, pc = $%04X\n", | ||
361 | (int) CPU_read( r.pc ), (unsigned) r.pc ); */ | ||
362 | |||
363 | return -1; | ||
364 | } | ||
365 | |||
366 | /* Catch DSP up to present */ | ||
367 | #if 0 | ||
368 | ENTER_TIMER(cpu); | ||
369 | #endif | ||
370 | SPC_run_dsp( this, -EXTRA_CLOCKS ); | ||
371 | #if 0 | ||
372 | EXIT_TIMER(cpu); | ||
373 | #endif | ||
374 | assert( this->next_dsp == CLOCKS_PER_SAMPLE - EXTRA_CLOCKS ); | ||
375 | assert( this->sample_buf - out == count ); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
diff --git a/apps/codecs/spc/spc_profiler.c b/apps/codecs/spc/spc_profiler.c new file mode 100644 index 0000000000..60e0ef7f82 --- /dev/null +++ b/apps/codecs/spc/spc_profiler.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | /* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */ | ||
21 | /* DSP Based on Brad Martin's OpenSPC DSP emulator */ | ||
22 | /* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */ | ||
23 | |||
24 | #if defined(SPC_PROFILE) && defined(USEC_TIMER) | ||
25 | |||
26 | #include "codec.h" | ||
27 | #include "spc_codec.h" | ||
28 | #define SPC_DEFINE_PROFILER_TIMERS | ||
29 | #include "spc_profiler.h" | ||
30 | |||
31 | void reset_profile_timers(void) | ||
32 | { | ||
33 | RESET_TIMER(total); | ||
34 | RESET_TIMER(render); | ||
35 | #if 0 | ||
36 | RESET_TIMER(cpu); | ||
37 | RESET_TIMER(dsp); | ||
38 | RESET_TIMER(dsp_pregen); | ||
39 | RESET_TIMER(dsp_gen); | ||
40 | RESET_TIMER(dsp_mix); | ||
41 | #endif | ||
42 | } | ||
43 | |||
44 | void print_timers(char * path) | ||
45 | { | ||
46 | int logfd = ci->open("/spclog.txt",O_WRONLY|O_CREAT|O_APPEND); | ||
47 | ci->fdprintf(logfd,"%s:\t",path); | ||
48 | ci->fdprintf(logfd,"%10ld total\t",READ_TIMER(total)); | ||
49 | PRINT_TIMER_PCT(render,total,"render"); | ||
50 | #if 0 | ||
51 | PRINT_TIMER_PCT(cpu,total,"CPU"); | ||
52 | PRINT_TIMER_PCT(dsp,total,"DSP"); | ||
53 | ci->fdprintf(logfd,"("); | ||
54 | PRINT_TIMER_PCT(dsp_pregen,dsp,"pregen"); | ||
55 | PRINT_TIMER_PCT(dsp_gen,dsp,"gen"); | ||
56 | PRINT_TIMER_PCT(dsp_mix,dsp,"mix"); | ||
57 | #endif | ||
58 | ci->fdprintf(logfd,"\n"); | ||
59 | |||
60 | ci->close(logfd); | ||
61 | logfd=-1; | ||
62 | } | ||
63 | |||
64 | #endif /* #if defined(SPC_PROFILE) && defined(USEC_TIMER) */ | ||
diff --git a/apps/codecs/spc/spc_profiler.h b/apps/codecs/spc/spc_profiler.h index 99d3fdf16b..330d95bca7 100644 --- a/apps/codecs/spc/spc_profiler.h +++ b/apps/codecs/spc/spc_profiler.h | |||
@@ -5,6 +5,7 @@ | |||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | ||
8 | * | 9 | * |
9 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) | 10 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) |
10 | * | 11 | * |
@@ -17,11 +18,19 @@ | |||
17 | ****************************************************************************/ | 18 | ****************************************************************************/ |
18 | 19 | ||
19 | /* a fun simple elapsed time profiler */ | 20 | /* a fun simple elapsed time profiler */ |
21 | #ifndef _SPC_PROFILER_H_ | ||
22 | #define _SPC_PROFILER_H_ | ||
20 | 23 | ||
21 | #if defined(SPC_PROFILE) && defined(USEC_TIMER) | 24 | #if defined(SPC_PROFILE) && defined(USEC_TIMER) |
22 | 25 | ||
23 | #define CREATE_TIMER(name) static uint32_t spc_timer_##name##_start,\ | 26 | #ifdef SPC_DEFINE_PROFILER_TIMERS |
27 | #define CREATE_TIMER(name) uint32_t spc_timer_##name##_start,\ | ||
24 | spc_timer_##name##_total | 28 | spc_timer_##name##_total |
29 | #else | ||
30 | #define CREATE_TIMER(name) extern uint32_t spc_timer_##name##_start,\ | ||
31 | spc_timer_##name##_total | ||
32 | #endif | ||
33 | |||
25 | #define ENTER_TIMER(name) spc_timer_##name##_start=USEC_TIMER | 34 | #define ENTER_TIMER(name) spc_timer_##name##_start=USEC_TIMER |
26 | #define EXIT_TIMER(name) spc_timer_##name##_total+=\ | 35 | #define EXIT_TIMER(name) spc_timer_##name##_total+=\ |
27 | (USEC_TIMER-spc_timer_##name##_start) | 36 | (USEC_TIMER-spc_timer_##name##_start) |
@@ -43,38 +52,8 @@ CREATE_TIMER(dsp_gen); | |||
43 | CREATE_TIMER(dsp_mix); | 52 | CREATE_TIMER(dsp_mix); |
44 | #endif | 53 | #endif |
45 | 54 | ||
46 | static void reset_profile_timers(void) { | 55 | void reset_profile_timers(void); |
47 | RESET_TIMER(total); | 56 | void print_timers(char * path); |
48 | RESET_TIMER(render); | ||
49 | #if 0 | ||
50 | RESET_TIMER(cpu); | ||
51 | RESET_TIMER(dsp); | ||
52 | RESET_TIMER(dsp_pregen); | ||
53 | RESET_TIMER(dsp_gen); | ||
54 | RESET_TIMER(dsp_mix); | ||
55 | #endif | ||
56 | } | ||
57 | |||
58 | static int logfd=-1; | ||
59 | |||
60 | static void print_timers(char * path) { | ||
61 | logfd = ci->open("/spclog.txt",O_WRONLY|O_CREAT|O_APPEND); | ||
62 | ci->fdprintf(logfd,"%s:\t",path); | ||
63 | ci->fdprintf(logfd,"%10ld total\t",READ_TIMER(total)); | ||
64 | PRINT_TIMER_PCT(render,total,"render"); | ||
65 | #if 0 | ||
66 | PRINT_TIMER_PCT(cpu,total,"CPU"); | ||
67 | PRINT_TIMER_PCT(dsp,total,"DSP"); | ||
68 | ci->fdprintf(logfd,"("); | ||
69 | PRINT_TIMER_PCT(dsp_pregen,dsp,"pregen"); | ||
70 | PRINT_TIMER_PCT(dsp_gen,dsp,"gen"); | ||
71 | PRINT_TIMER_PCT(dsp_mix,dsp,"mix"); | ||
72 | #endif | ||
73 | ci->fdprintf(logfd,"\n"); | ||
74 | |||
75 | ci->close(logfd); | ||
76 | logfd=-1; | ||
77 | } | ||
78 | 57 | ||
79 | #else | 58 | #else |
80 | 59 | ||
@@ -87,3 +66,5 @@ static void print_timers(char * path) { | |||
87 | #define reset_profile_timers() | 66 | #define reset_profile_timers() |
88 | 67 | ||
89 | #endif | 68 | #endif |
69 | |||
70 | #endif /* _SPC_PROFILER_H_ */ | ||