1 /*********************************************************************
2 * file.c - dsp patch manager library - patch file reading functions
4 * Copyright (C) 2000 Rui Sousa
5 *********************************************************************
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
20 *********************************************************************
24 #include "../emu10k1-include/dsp.h"
25 #include "../emu10k1-include/list.h"
27 #include "../emu10k1-include/internal.h"
29 extern __u32 addr_change
[0x400];
32 #define FILE_HEAD "emu10k1-dsp-file"
33 #define FILE_FORMAT_VERSION 1
35 /* gives an increasing id to patches with the same name */
36 static int set_patch_id(struct dsp_patch_manager
*mgr
, struct dsp_patch
*patch
)
38 struct dsp_patch
*patch1
;
39 struct list_head
*entry
;
45 list_for_each(entry
, &mgr
->ipatch_list
) {
46 patch1
= list_entry(entry
, struct dsp_patch
, list
);
48 if (!strcmp(patch1
->name
, patch
->name
)) {
49 table
[patch1
->id
] = 1;
50 while (table
[patch
->id
] == 1) {
59 list_for_each(entry
, &mgr
->opatch_list
) {
60 patch1
= list_entry(entry
, struct dsp_patch
, list
);
62 if (!strcmp(patch1
->name
, patch
->name
)) {
63 table
[patch1
->id
] = 1;
64 while (table
[patch
->id
] == 1) {
74 static int read_patch_code(struct dsp_patch
*patch
, FILE * fp
)
76 patch
->code
= (__u32
*) malloc(patch
->code_size
* sizeof(__u32
));
78 if (patch
->code
== NULL
) {
79 fprintf(stderr
, "read_patch_code(): no memory available\n");
83 fread(patch
->code
, sizeof(__u32
), patch
->code_size
, fp
);
89 /* Still missing the ALIGN and CLEAR bits */
90 static inline void read_tram_lines(__u32 tramb_start
, __u32
* traml_addr
,
91 __u8
* traml_size
, __u16 base
, __u32 type
, FILE * fp
)
98 fread(&lines
, sizeof(__u8
), 1, fp
);
99 for (i
= 0; i
< lines
; i
++) {
100 fread(&data_addr
, sizeof(__u8
), 1, fp
);
102 addr_change
[TRAML_IDATA_BASE
- GPR_BASE
+ data_addr
] = base
+ *traml_size
;
104 addr_change
[TRAML_IADDR_BASE
- GPR_BASE
+ data_addr
] =
105 base
+ (TRAML_IADDR_BASE
- TRAML_IDATA_BASE
) + *traml_size
;
107 fread(&addr_val
, sizeof(__u32
), 1, fp
);
109 traml_addr
[*traml_size
] = ((tramb_start
+ addr_val
) & 0xfffff) | (type
<< 20);
114 /* FIXME restore tramb_?start on failure */
115 static int read_tram_block(struct dsp_patch_manager
*mgr
, struct dsp_patch
*patch
, __u32
* traml_iaddr
,
116 __u32
* traml_eaddr
, FILE * fp
)
123 /* tram blocks and lines */
124 fread(&blocks
, sizeof(__u8
), 1, fp
);
125 for (i
= 0; i
< blocks
; i
++) {
126 fread(&size
, sizeof(__u32
), 1, fp
);
128 type
= 0x30000000 & size
;
132 fprintf(stderr
, "tram block of 0 size\n");
136 if ( (size
<= TRAMB_ISIZE
- mgr
->tramb_ifree_start
) && (type
!=TRAM_EXTERNAL
)) {
137 tmp
= patch
->traml_isize
;
141 read_tram_lines(patch
->tramb_isize
,
142 traml_iaddr
, &patch
->traml_isize
, TRAML_IDATA_BASE
, TRAML_TYPE_WRITE
, fp
);
145 read_tram_lines(patch
->tramb_isize
,
146 traml_iaddr
, &patch
->traml_isize
, TRAML_IDATA_BASE
, TRAML_TYPE_READ
, fp
);
148 /* a block with no tram lines */
149 if (tmp
== patch
->traml_isize
) {
150 fprintf(stderr
, "tram block with no tram lines\n");
154 /* no free tram space */
155 if (mgr
->traml_ifree_start
+ patch
->traml_isize
> TRAML_ISIZE
) {
156 fprintf(stderr
, "no free internal tram lines\n");
160 patch
->tramb_isize
+= size
;
161 mgr
->tramb_ifree_start
+= size
;
163 } else if ((size
<= TRAMB_ESIZE
- mgr
->tramb_efree_start
)&&(type
!=TRAM_INTERNAL
)) {
164 tmp
= patch
->traml_esize
;
168 read_tram_lines(patch
->tramb_esize
, traml_eaddr
,
169 &patch
->traml_esize
, TRAML_EDATA_BASE
, TRAML_TYPE_WRITE
, fp
);
173 read_tram_lines(patch
->tramb_esize
, traml_eaddr
,
174 &patch
->traml_esize
, TRAML_EDATA_BASE
, TRAML_TYPE_READ
, fp
);
176 /* a block with no tram lines */
177 if (tmp
== patch
->traml_esize
) {
178 fprintf(stderr
, "tram block with no tram lines\n");
182 /* no free tram space */
183 if (mgr
->traml_efree_start
+ patch
->traml_esize
> TRAML_ESIZE
) {
184 fprintf(stderr
, "no free external tram lines\n");
187 patch
->tramb_esize
+= size
;
188 mgr
->tramb_efree_start
+= size
;
191 fprintf(stderr
, "no free tram blocks\n");
196 mgr
->traml_ifree_start
+= patch
->traml_isize
;
197 mgr
->traml_efree_start
+= patch
->traml_esize
;
203 /* only single input patches supported */
204 static int read_patch_header(struct dsp_patch_manager
*mgr
, struct dsp_patch
*patch
, FILE * fp
, char *name
, int num_in
, int num_out
)
206 char tmp
[sizeof(FILE_HEAD
)];
208 __u32 traml_iaddr
[TRAML_ISIZE
];
209 __u32 traml_eaddr
[TRAML_ESIZE
];
211 __u8 input
[DSP_NUM_INPUTS
],output
[DSP_NUM_OUTPUTS
];
214 //Read file format info:
215 fread(tmp
, sizeof(char), sizeof(FILE_HEAD
), fp
);
216 if(strcmp(tmp
,FILE_HEAD
)){
217 fprintf(stderr
,"Error: File is not a proper dsp file\n" );
220 //Read format version
222 fread(&i
, sizeof(__u16
),1 , fp
);
224 if( i
< FILE_FORMAT_VERSION
)
225 fprintf(stderr
,"Warning: file was created with a newer version of the emu-tools\n");
230 fread(patch
->name
, sizeof(char), DSP_PATCH_NAME_SIZE
, fp
);
232 //If user specifies a different patch name, we change it now:
234 strncpy(patch
->name
,name
, DSP_LINE_NAME_SIZE
);
235 patch
->name
[DSP_LINE_NAME_SIZE
- 1] = '\0';
237 //we copy back the name in the patch
238 strncpy(name
, patch
->name
, DSP_LINE_NAME_SIZE
);
240 /* input/output gprs */
241 fread(&count
, sizeof(__u8
), 1, fp
);
244 // We'll need to change the file format to support non-symetric I/O
246 fprintf(stderr
,"Patch requires %d inputs, %d were specified\n",count
,num_in
);
251 for (i
= 0; i
< count
; i
++) {
252 fread(&(input
[i
]), sizeof(__u8
), 1, fp
);
253 fread(&(output
[i
]), sizeof(__u8
), 1, fp
);
257 for(i
=0;i
<DSP_NUM_INPUTS
;i
++){
258 if(patch_uses_input(patch
,i
)){
259 addr_change
[input
[j
]] = get_io_gpr(mgr
, i
, GPR_INPUT
, patch
->gpr_used
, patch
->gpr_input
);
265 for(i
=0;i
<DSP_NUM_OUTPUTS
;i
++){
266 if(patch_uses_output(patch
,i
)){
267 addr_change
[output
[j
]] = get_io_gpr(mgr
, i
, GPR_OUTPUT
, patch
->gpr_used
, patch
->gpr_input
);
273 fread(&count
, sizeof(__u8
), 1, fp
);
274 for (i
= 0; i
< count
; i
++) {
275 fread(&addr
, sizeof(__u8
), 1, fp
);
276 addr_change
[addr
] = get_dynamic_gpr(mgr
, patch
->gpr_used
);
280 fread(&count
, sizeof(__u8
), 1, fp
);
281 for (i
= 0; i
< count
; i
++) {
283 fread(&addr
, sizeof(__u8
), 1, fp
);
284 fread(&value
, sizeof(__s32
), 1, fp
);
285 addr_change
[addr
] = get_static_gpr(mgr
, value
, patch
->gpr_used
);
289 fread(&count
, sizeof(__u8
), 1, fp
);
290 for (i
= 0; i
< count
; i
++) {
291 __s32 value
, min
, max
;
292 char name
[DSP_GPR_NAME_SIZE
];
294 fread(&addr
, sizeof(__u8
), 1, fp
);
295 fread(&value
, sizeof(__s32
), 1, fp
);
296 fread(&min
, sizeof(__s32
), 1, fp
);
297 fread(&max
, sizeof(__s32
), 1, fp
);
300 fprintf(stderr
, "invalid range for control gpr %x %x\n", min
, max
);
306 else if (value
< min
)
309 fread(name
, sizeof(char), DSP_GPR_NAME_SIZE
, fp
);
311 addr_change
[addr
] = get_control_gpr(mgr
, value
, min
, max
, name
, patch
->gpr_used
, patch
->name
);
315 fread(&count
, sizeof(__u8
), 1, fp
);
316 for (i
= 0; i
< count
; i
++) {
319 fread(&addr
, sizeof(__u8
), 1, fp
);
320 fread(&value
, sizeof(__s32
), 1, fp
);
321 addr_change
[addr
] = get_constant_gpr(mgr
, value
, patch
->gpr_used
);
323 /* here lines and blocks, internal and external, all start from 0 */
324 /* this is fixed later on in set_tram_addr() */
326 patch
->tramb_istart
= 0;
327 patch
->tramb_isize
= 0;
328 patch
->tramb_estart
= 0;
329 patch
->tramb_esize
= 0;
331 patch
->traml_istart
= 0;
332 patch
->traml_isize
= 0;
334 patch
->traml_estart
= 0;
335 patch
->traml_esize
= 0;
337 /* tram tablelookup blocks and lines */
338 ret
= read_tram_block(mgr
, patch
, traml_iaddr
, traml_eaddr
, fp
);
342 /* tram delaylines blocks and lines */
343 ret
= read_tram_block(mgr
, patch
, traml_iaddr
, traml_eaddr
, fp
);
347 if (patch
->traml_isize
!= 0) {
348 patch
->traml_iaddr
= (__u32
*) malloc(patch
->traml_isize
* sizeof(__u32
));
349 if (patch
->traml_iaddr
== NULL
) {
350 fprintf(stderr
, "read_patch_header(): no memory available\n");
353 memcpy(patch
->traml_iaddr
, traml_iaddr
, patch
->traml_isize
* sizeof(__u32
));
356 if (patch
->traml_esize
!= 0) {
357 patch
->traml_eaddr
= (__u32
*) malloc(patch
->traml_esize
* sizeof(__u32
));
358 if (patch
->traml_eaddr
== NULL
) {
359 fprintf(stderr
, "read_patch_header(): no memory available\n");
362 memcpy(patch
->traml_eaddr
, traml_eaddr
, patch
->traml_esize
* sizeof(__u32
));
365 fread(&patch
->code_size
, sizeof(__u16
), 1, fp
);
367 if (patch
->code_size
== 0) {
368 fprintf(stderr
, "patch with zero code size\n");
372 mgr
->code_free_start
+= patch
->code_size
;
374 if (mgr
->code_free_start
> DSP_CODE_SIZE
) {
375 fprintf(stderr
, "no free dsp code memory\n");
382 mgr
->code_free_start
-= patch
->code_size
;
385 if (patch
->traml_esize
!= 0)
386 free(patch
->traml_eaddr
);
389 if (patch
->traml_isize
!= 0)
390 free(patch
->traml_iaddr
);
396 /* support precise patch positioning in a line (patches in general don't commute) */
398 int dsp_read_patch(struct dsp_patch_manager
*mgr
, const char *file
, int input
[DSP_NUM_INPUTS
],
399 int output
[DSP_NUM_OUTPUTS
], int num_in
, int num_out
, int io
, char *name
, int placement
)
401 struct dsp_patch
*patch
;
402 struct list_head
*list
;
407 fprintf(stderr
,"Error: Patches with an unequal number of ins and outs are not yet supported\n");
412 patch
= (struct dsp_patch
*) malloc(sizeof(struct dsp_patch
));
417 memset(patch
, 0, sizeof(struct dsp_patch
));
420 if ((fp
= fopen(file
, "r")) == NULL
) {
428 list
= &mgr
->ipatch_list
;
429 /* only load a patch if there is a route connecting it */
430 for(i
=0;i
<num_in
;i
++){
431 set_bit(input
[i
], &patch
->input
);
432 set_bit(output
[i
], &patch
->output
);
434 for (j
= 0; j
< DSP_NUM_OUTPUTS
; j
++)
435 if ( test_bit(input
[i
], &mgr
->rpatch
.route_v
[j
]) || test_bit(input
[i
], &mgr
->rpatch
.route
[j
]) )
442 list
=&mgr
->opatch_list
;
443 /* only load a patch if there is a route connecting it */
444 for(i
=0;i
<num_out
;i
++){
445 set_bit(input
[i
], &patch
->input
);
446 set_bit(output
[i
], &patch
->output
);
447 if ( !( mgr
->rpatch
.route_v
[input
[i
]] || mgr
->rpatch
.route
[input
[i
]]))
467 if (read_patch_header(mgr
, patch
, fp
, name
, num_in
, num_out
) < 0)
470 read_patch_code(patch
, fp
);
471 search_and_replace(patch
->code
, patch
->code_size
, addr_change
, GPR_BASE
, TRAML_EADDR_BASE
+ TRAML_ESIZE
);
473 set_patch_id(mgr
, patch
);
474 determine_io(mgr
, patch
);
477 list_add(&patch
->list
, list
);
479 list_add_tail(&patch
->list
, list
);