/*
* EMU10k1 loader lib
* Copyright (c) 2003,2004 by Peter Zubaj
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "ld10k1_error.h"
#include "ld10k1_fnc.h"
#include "comm.h"
#include "liblo10k1.h"
#include "liblo10k1ef.h"
#define AS10K1_FILE_SIGNATURE_ALSA "EMU10K1 FX8010 1"
#define AS10K1_FILE_SIGNATURE_EMU "emu10k1-dsp-file"
#define AS10K1_FILE_FORMAT_VERSION_EMU 1
liblo10k1_emu_patch_t *liblo10k1_emu_new_patch()
{
liblo10k1_emu_patch_t *tmp = (liblo10k1_emu_patch_t *)malloc(sizeof(liblo10k1_emu_patch_t));
if (!tmp)
return NULL;
memset(tmp, 0, sizeof(liblo10k1_emu_patch_t));
return tmp;
}
void liblo10k1_emu_free_patch(liblo10k1_emu_patch_t *p)
{
liblo10k1_emu_patch_set_in_count(p, 0);
liblo10k1_emu_patch_set_out_count(p, 0);
liblo10k1_emu_patch_set_dyn_count(p, 0);
liblo10k1_emu_patch_set_sta_count(p, 0);
liblo10k1_emu_patch_set_ctl_count(p, 0);
liblo10k1_emu_patch_set_con_count(p, 0);
liblo10k1_emu_patch_set_lookup_count(p, 0);
liblo10k1_emu_patch_set_delay_count(p, 0);
liblo10k1_emu_patch_set_instr_count(p, 0);
free(p);
}
int liblo10k1_emu_patch_set_in_count(liblo10k1_emu_patch_t *p, int count)
{
unsigned int *tmp = NULL;
if (count > 0) {
tmp = (unsigned int *)malloc(sizeof(unsigned int)*count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(unsigned int) * count);
}
p->in_count = count;
if (p->ins)
free(p->ins);
p->ins = tmp;
return 0;
}
int liblo10k1_emu_patch_set_out_count(liblo10k1_emu_patch_t *p, int count)
{
unsigned int *tmp = NULL;
if (count > 0) {
tmp = (unsigned int *)malloc(sizeof(unsigned int)*count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(unsigned int) * count);
}
p->out_count = count;
if (p->outs)
free(p->outs);
p->outs = tmp;
return 0;
}
int liblo10k1_emu_patch_set_dyn_count(liblo10k1_emu_patch_t *p, int count)
{
unsigned int *tmp = NULL;
if (count > 0) {
tmp = (unsigned int *)malloc(sizeof(unsigned int)*count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(unsigned int) * count);
}
p->dyn_count = count;
if (p->dyns)
free(p->dyns);
p->dyns = tmp;
return 0;
}
int liblo10k1_emu_patch_set_sta_count(liblo10k1_emu_patch_t *p, int count)
{
liblo10k1_emu_sc_t *tmp = NULL;
if (count > 0) {
tmp = (liblo10k1_emu_sc_t *)malloc(sizeof(liblo10k1_emu_sc_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_sc_t)*count);
}
p->sta_count = count;
if (p->stas)
free(p->stas);
p->stas = tmp;
return 0;
}
int liblo10k1_emu_patch_set_ctl_count(liblo10k1_emu_patch_t *p, int count)
{
liblo10k1_emu_ctl_t *tmp = NULL;
if (count > 0) {
tmp = (liblo10k1_emu_ctl_t *)malloc(sizeof(liblo10k1_emu_ctl_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_ctl_t)*count);
}
p->ctl_count = count;
if (p->ctls)
free(p->ctls);
p->ctls = tmp;
return 0;
}
int liblo10k1_emu_patch_set_con_count(liblo10k1_emu_patch_t *p, int count)
{
liblo10k1_emu_sc_t *tmp = NULL;
if (count > 0) {
tmp = (liblo10k1_emu_sc_t *)malloc(sizeof(liblo10k1_emu_sc_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_sc_t)*count);
}
p->con_count = count;
if (p->cons)
free(p->cons);
p->cons = tmp;
return 0;
}
int liblo10k1_emu_patch_set_line_count(liblo10k1_emu_tram_t *t, int write, int count)
{
liblo10k1_emu_tram_line_t *tmp = NULL;
if (count > 0) {
tmp = (liblo10k1_emu_tram_line_t *)malloc(sizeof(liblo10k1_emu_tram_line_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_tram_line_t)*count);
}
if (write) {
t->write_line_count = count;
if (t->write_lines)
free(t->write_lines);
t->write_lines = tmp;
} else {
t->read_line_count = count;
if (t->read_lines)
free(t->read_lines);
t->read_lines = tmp;
}
return 0;
}
int liblo10k1_emu_patch_set_lookup_count(liblo10k1_emu_patch_t *p, int count)
{
liblo10k1_emu_tram_t *tmp = NULL;
int i;
if (count > 0) {
tmp = (liblo10k1_emu_tram_t *)malloc(sizeof(liblo10k1_emu_tram_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_tram_t)*count);
}
if (p->tram_lookups) {
for (i = 0; i < p->tram_lookup_count; i++) {
liblo10k1_emu_patch_set_line_count(&(p->tram_lookups[i]), 0, 0);
liblo10k1_emu_patch_set_line_count(&(p->tram_lookups[i]), 1, 0);
}
free(p->tram_lookups);
}
p->tram_lookup_count = count;
p->tram_lookups = tmp;
return 0;
}
int liblo10k1_emu_patch_set_delay_count(liblo10k1_emu_patch_t *p, int count)
{
liblo10k1_emu_tram_t *tmp = NULL;
int i;
if (count > 0) {
tmp = (liblo10k1_emu_tram_t *)malloc(sizeof(liblo10k1_emu_tram_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_tram_t)*count);
}
if (p->tram_delays) {
for (i = 0; i < p->tram_delay_count; i++) {
liblo10k1_emu_patch_set_line_count(&(p->tram_delays[i]), 0, 0);
liblo10k1_emu_patch_set_line_count(&(p->tram_delays[i]), 1, 0);
}
free(p->tram_delays);
}
p->tram_delay_count = count;
p->tram_delays = tmp;
return 0;
}
int liblo10k1_emu_patch_set_instr_count(liblo10k1_emu_patch_t *p, int count)
{
liblo10k1_emu_instr_t *tmp = NULL;
if (count > 0) {
tmp = (liblo10k1_emu_instr_t *)malloc(sizeof(liblo10k1_emu_instr_t) * count);
if (!tmp)
return LD10K1_ERR_NO_MEM;
memset(tmp, 0, sizeof(liblo10k1_emu_instr_t)*count);
}
p->instr_count = count;
if (p->instrs)
free(p->instrs);
p->instrs = tmp;
return 0;
}
static int read_byte(char *patch_data, int size, int *pos, unsigned char *out)
{
if (*pos < size) {
*out = patch_data[*pos];
(*pos)++;
return 0;
} else
return LD10K1_EF_ERR_FORMAT;
}
static int read_ushort(char *patch_data, int size, int *pos, unsigned short *out)
{
if (*pos + 1 < size) {
*out = *((unsigned short *)(patch_data + *pos));
*(pos) += 2;
return 0;
} else
return LD10K1_EF_ERR_FORMAT;
}
static int read_uint(char *patch_data, int size, int *pos, unsigned int *out)
{
if (*pos + 3 < size) {
*out = *((unsigned int *)(patch_data + *pos));
(*pos) += 4;
return 0;
} else
return LD10K1_EF_ERR_FORMAT;
}
static int read_string(char *patch_data, int size, int *pos, char *out, int ssize)
{
if (*pos + ssize - 1 < size) {
strncpy(out, &(patch_data[*pos]), ssize - 1);
out[ssize - 1] = '\0';
(*pos) += ssize;
return 0;
} else
return LD10K1_EF_ERR_FORMAT;
}
int liblo10k1_emu_load_patch(char *file_name, liblo10k1_emu_patch_t **p)
{
struct stat patch_stat;
char *patch_data;
FILE *patch_file;
liblo10k1_emu_patch_t *new_patch = NULL;
unsigned int i, j, z, k;
int en = 0;
int file_pos = 0;
int file_size = 0;
unsigned char byte_tmp;
unsigned short ushort_tmp;
liblo10k1_emu_tram_t *tmp_tram;
liblo10k1_emu_tram_line_t *tmp_tram_lines;
unsigned int part1, part2;
if (!(patch_file = fopen(file_name, "r")))
return LD10K1_EF_ERR_OPEN;
/* first load patch to mem */
if (stat(file_name, &patch_stat))
return LD10K1_EF_ERR_STAT;
/* minimal patch len is 57 */
if (patch_stat.st_size < 57 || patch_stat.st_size > 1000000)
return LD10K1_EF_ERR_SIZE;
file_size = patch_stat.st_size;
patch_data = (char *)malloc(patch_stat.st_size);
if (!patch_data)
return LD10K1_ERR_NO_MEM;
if (fread(patch_data, patch_stat.st_size, 1, patch_file) != 1) {
fclose(patch_file);
en = LD10K1_EF_ERR_READ;
goto err;
} else
fclose(patch_file);
int file_sig = 0;
/* signature checks - two kinds of as10k1 files, one from alsa-tools, other from emu-tools. */
if(strncmp(patch_data, AS10K1_FILE_SIGNATURE_ALSA, 16) != 0)
{
if((strncmp(patch_data, AS10K1_FILE_SIGNATURE_EMU, 16) == 0) && (*((unsigned short *)&patch_data[17]) == AS10K1_FILE_FORMAT_VERSION_EMU))
file_sig = 3;
else
{
en = LD10K1_EF_ERR_SIGNATURE;
goto err;
}
}
new_patch = liblo10k1_emu_new_patch();
if (!new_patch) {
en = LD10K1_ERR_NO_MEM;
goto err;
}
/* next patch name */
strncpy(new_patch->patch_name, &(patch_data[16 + file_sig]), 31);
new_patch->patch_name[31] = '\0';
/* registers */
file_pos = 32+16 + file_sig;
/* in count */
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if (byte_tmp >= 32) {
en = LD10K1_EF_ERR_FORMAT;
goto err;
}
if ((en = liblo10k1_emu_patch_set_in_count(new_patch, byte_tmp)) < 0 ||
(en = liblo10k1_emu_patch_set_out_count(new_patch, byte_tmp)) < 0)
goto err;
/* read in gprs */
for (i = 0; i < new_patch->in_count; i++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
new_patch->ins[i] = byte_tmp;
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
new_patch->outs[i] = byte_tmp;
}
/* read dyn gprs */
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if ((en = liblo10k1_emu_patch_set_dyn_count(new_patch, byte_tmp)) < 0)
goto err;
for (i = 0; i < new_patch->dyn_count; i++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
new_patch->dyns[i] = byte_tmp;
}
/* read sta gprs */
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if ((en = liblo10k1_emu_patch_set_sta_count(new_patch, byte_tmp)) < 0)
goto err;
for (i = 0; i < new_patch->sta_count; i++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
new_patch->stas[i].sc = byte_tmp;
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->stas[i].sc_val))) < 0)
goto err;
}
/* read ctl gprs */
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if ((en = liblo10k1_emu_patch_set_ctl_count(new_patch, byte_tmp)) < 0)
goto err;
for (i = 0; i < new_patch->ctl_count; i++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
new_patch->ctls[i].ctl = byte_tmp;
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->ctls[i].ctl_val))) < 0)
goto err;
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->ctls[i].ctl_val_min))) < 0)
goto err;
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->ctls[i].ctl_val_max))) < 0)
goto err;
if ((en = read_string(patch_data, file_size, &file_pos, new_patch->ctls[i].ctl_name, 32)) < 0)
goto err;
}
/* read const gprs */
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if ((en = liblo10k1_emu_patch_set_con_count(new_patch, byte_tmp)) < 0)
goto err;
for (i = 0; i < new_patch->con_count; i++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
new_patch->cons[i].sc = byte_tmp;
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->cons[i].sc_val))) < 0)
goto err;
}
/* read tram lookup gprs */
for (z = 0; z < 2; z++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if (z) {
if ((en = liblo10k1_emu_patch_set_delay_count(new_patch, byte_tmp)) < 0)
goto err;
} else {
if ((en = liblo10k1_emu_patch_set_lookup_count(new_patch, byte_tmp)) < 0)
goto err;
}
for (i = 0; i < (z ? new_patch->tram_delay_count : new_patch->tram_lookup_count); i++) {
/* size */
if (z) {
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->tram_delays[i].size))) < 0)
goto err;
tmp_tram = new_patch->tram_delays + i;
} else {
if ((en = read_uint(patch_data, file_size, &file_pos, &(new_patch->tram_lookups[i].size))) < 0)
goto err;
tmp_tram = new_patch->tram_lookups + i;
}
for (k = 0; k < 2; k++) {
/* read lines */
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
if ((en = liblo10k1_emu_patch_set_line_count(tmp_tram, k, byte_tmp)) < 0)
goto err;
if (k)
tmp_tram_lines = tmp_tram->write_lines;
else
tmp_tram_lines = tmp_tram->read_lines;
for (j = 0; j < (k ? tmp_tram->write_line_count : tmp_tram->read_line_count); j++) {
if ((en = read_byte(patch_data, file_size, &file_pos, &byte_tmp)) < 0)
goto err;
tmp_tram_lines[j].line = byte_tmp;
if ((en = read_uint(patch_data, file_size, &file_pos, &(tmp_tram_lines[j].line_size))) < 0)
goto err;
}
}
}
}
/* instruction lines */
if ((en = read_ushort(patch_data, file_size, &file_pos, &ushort_tmp)) < 0)
goto err;
if(file_sig)
ushort_tmp >>= 1;
if ((en = liblo10k1_emu_patch_set_instr_count(new_patch, ushort_tmp)) < 0)
goto err;
for (i = 0; i < new_patch->instr_count; i++) {
if ((en = read_uint(patch_data, file_size, &file_pos, &part1)) < 0)
goto err;
if ((en = read_uint(patch_data, file_size, &file_pos, &part2)) < 0)
goto err;
/* fill instr */
new_patch->instrs[i].arg[2] = part1 >> 10;
new_patch->instrs[i].arg[3] = part1 & 0x3FF;
new_patch->instrs[i].op = part2 >> 20;
new_patch->instrs[i].arg[0] = (part2 >> 10) & 0x3FF;
new_patch->instrs[i].arg[1] = part2 & 0x3FF;
}
*p = new_patch;
if (patch_data)
free(patch_data);
return 0;
err:
if (patch_data)
free(patch_data);
if (new_patch)
liblo10k1_emu_free_patch(new_patch);
return en;
}
typedef struct
{
unsigned int gpr;
unsigned int ld_gpr;
} used_gpr_t;
static int check_if_used(used_gpr_t *gprs, int count, unsigned int gpr)
{
int i;
for (i = 0; i < count; i++) {
if (gprs[i].gpr == gpr)
return i;
}
return -1;
}
static char *default_in_names[] =
{
"IL",
"IR",
"IRL",
"IRR",
"IC",
"ILFE"
};
static char *default_out_names[] =
{
"OL",
"OR",
"ORL",
"ORR",
"OC",
"OLFE"
};
int liblo10k1_patch_find_ctl_by_name(liblo10k1_dsp_patch_t *p, char *ctl_name)
{
int i;
for (i = 0; i < p->ctl_count; i++)
if (strcmp(p->ctl[i].name, ctl_name) == 0)
return i;
return -1;
}
int liblo10k1_patch_ctl_set_trans(liblo10k1_dsp_patch_t *p, int idx, int trans)
{
int i;
switch (trans) {
case EMU10K1_GPR_TRANSLATION_NONE:
break;
case EMU10K1_GPR_TRANSLATION_TABLE100:
if (p->ctl[idx].min != 0 && p->ctl[idx].max != 100)
return LD10K1_EF_ERR_TRANSFORM_TRANS;
break;
case EMU10K1_GPR_TRANSLATION_BASS:
case EMU10K1_GPR_TRANSLATION_TREBLE:
if (p->ctl[idx].min != 0 && p->ctl[idx].max != 0xFFFFFFFF)
return LD10K1_EF_ERR_TRANSFORM_TRANS;
if (p->ctl[idx].count != 5)
return LD10K1_EF_ERR_TRANSFORM_TRANS;
break;
case EMU10K1_GPR_TRANSLATION_ONOFF:
if (p->ctl[idx].min != 0 && p->ctl[idx].max != 1)
return LD10K1_EF_ERR_TRANSFORM_TRANS;
break;
}
for (i = 0; i < p->ctl[idx].count; i++)
if (p->ctl[idx].value[i] < p->ctl[idx].min || p->ctl[idx].value[i] > p->ctl[idx].max)
return LD10K1_EF_ERR_TRANSFORM_TRANS;
p->ctl[idx].translation = trans;
return 0;
}
int liblo10k1_patch_ctl_set_vcount(liblo10k1_dsp_patch_t *p, int idx, int vc)
{
if (p->ctl[idx].count < vc)
return LD10K1_EF_ERR_TRANSFORM_CTL;
p->ctl[idx].vcount = vc;
return 0;
}
int liblo10k1_patch_ctl_set_index(liblo10k1_dsp_patch_t *p, int idx, int i)
{
p->ctl[idx].index = i;
return 0;
}
int liblo10k1_patch_ctl_set_value(liblo10k1_dsp_patch_t *p, int idx, int vi, int val)
{
if (p->ctl[idx].count < vi)
return LD10K1_EF_ERR_TRANSFORM_CTL;
if (val < p->ctl[idx].min || val > p->ctl[idx].max)
return LD10K1_EF_ERR_TRANSFORM_CTL;
p->ctl[idx].value[vi] = val;
return 0;
}
int liblo10k1_emu_transform_patch(liblo10k1_emu_patch_t *ep, liblo10k1_ctl_transform_t *tctl, int tctl_count, liblo10k1_dsp_patch_t **lp)
{
used_gpr_t used_gpr[0x400];
int used_gpr_count = 0;
int i, j, k;
int gpr;
int tmp_cnt;
int idx;
int en = 0;
int io_name_map[6];
int transformed;
liblo10k1_dsp_ctl_t *tmp_nctl;
liblo10k1_emu_ctl_t *tmp_octl;
int const_count, hw_count; /*int ctl_transform_map[256];*/
liblo10k1_dsp_patch_t *np = NULL;
liblo10k1_emu_tram_t *tram_tmp;
liblo10k1_dsp_tram_acc_t *tram_nacc;
liblo10k1_emu_tram_line_t *tram_line;
int val, addhw, addconst;
/* for all instruction get used gpr list */
for (i = 0; i < ep->instr_count; i++) {
for (j = 0; j < 4; j++) {
gpr = ep->instrs[i].arg[j];
for (k = 0; k < used_gpr_count; k++)
if (gpr == used_gpr[k].gpr)
break;
if (k < used_gpr_count)
continue;
used_gpr[used_gpr_count].gpr = gpr;
used_gpr[used_gpr_count].ld_gpr = 0;
used_gpr_count++;
}
}
np = liblo10k1_patch_alloc(0, 0, 0, 0, 0, 0, 0, 0, 0, ep->instr_count);
if (!np)
return LD10K1_ERR_NO_MEM;
/* set patch name */
strcpy(np->patch_name, ep->patch_name);
/* in gprs */
tmp_cnt = 0;
for (i = 0; i < ep->in_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->ins[i] + 0x100);
if (idx >= 0) {
used_gpr[idx].ld_gpr = EMU10K1_PREG_IN(tmp_cnt);
if (i < 6)
io_name_map[i] = tmp_cnt;
tmp_cnt++;
} else {
if (i < 6)
io_name_map[i] = -1;
}
}
if ((en = liblo10k1_patch_set_in_count(np, tmp_cnt)) < 0)
goto err;
/* set in name */
if (ep->in_count == 2 || /* stereo */
ep->in_count == 4 || /* 4 channel */
ep->in_count == 6) { /* 5.1 */
for (i = 0; i < ep->in_count; i++) {
if (io_name_map[i] >= 0)
strcpy(np->ins[io_name_map[i]].name, default_in_names[i]);
}
}
/* out gprs */
tmp_cnt = 0;
for (i = 0; i < ep->out_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->outs[i] + 0x100);
if (idx >= 0) {
used_gpr[idx].ld_gpr = EMU10K1_PREG_OUT(tmp_cnt);
if (i < 6)
io_name_map[i] = tmp_cnt;
tmp_cnt++;
} else {
if (i < 6)
io_name_map[i] = -1;
}
}
if ((en = liblo10k1_patch_set_out_count(np, tmp_cnt)) < 0)
goto err;
/* set out name */
if (ep->out_count == 2 || /* stereo */
ep->out_count == 4 || /* 4 channel */
ep->out_count == 6) { /* 5.1 */
for (i = 0; i < ep->out_count; i++) {
if (io_name_map[i] >= 0)
strcpy(np->outs[io_name_map[i]].name, default_out_names[i]);
}
}
/* dyn regs */
tmp_cnt = 0;
for (i = 0; i < ep->dyn_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->dyns[i] + 0x100);
if (idx >= 0) {
used_gpr[idx].ld_gpr = EMU10K1_PREG_DYN(tmp_cnt);
tmp_cnt++;
}
}
if ((en = liblo10k1_patch_set_dyn_count(np, tmp_cnt)) < 0)
goto err;
/* sta regs */
tmp_cnt = 0;
for (i = 0; i < ep->sta_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->stas[i].sc + 0x100);
if (idx >= 0) {
used_gpr[idx].ld_gpr = EMU10K1_PREG_STA(tmp_cnt);
tmp_cnt++;
}
}
if ((en = liblo10k1_patch_set_sta_count(np, tmp_cnt)) < 0)
goto err;
/* sta regs - initilization */
tmp_cnt = 0;
for (i = 0; i < ep->sta_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->stas[i].sc + 0x100);
if (idx >= 0) {
np->stas[tmp_cnt].const_val = ep->stas[i].sc_val;
tmp_cnt++;
}
}
/* FIXME - ak je niektoty ctl pouzity v tctl viackrat tak to zblbne */
/* ctls regs */
/* first get count of ctls */
tmp_cnt = 0;
for (i = 0; i < tctl_count; i++)
tmp_cnt += tctl[i].emu_ctl_count;
if ((en = liblo10k1_patch_set_ctl_count(np, ep->ctl_count - tmp_cnt + tctl_count)) < 0)
goto err;
tmp_cnt = 0;
for (i = 0; i < ep->ctl_count; i++) {
tmp_octl = &(ep->ctls[i]);
/* find if transformed */
transformed = 0;
for (j = 0; j < tctl_count; j++) {
for (k = 0; k < tctl[j].emu_ctl_count; k++) {
if (i == tctl[j].emu_ctls[k]) {
/* it is transformed */
tmp_nctl = &(np->ctl[j]);
if (strcmp(tmp_nctl->name, "") != 0) {
/* initialized - check min, max */
if (tmp_octl->ctl_val_min != tmp_nctl->min ||
tmp_octl->ctl_val_max != tmp_nctl->max) {
en = LD10K1_EF_ERR_TRANSFORM_CTL;
goto err;
}
tmp_nctl->value[k] = tmp_octl->ctl_val;
} else {
/* initialize it */
strcpy(tmp_nctl->name, tctl[j].ctl_name);
tmp_nctl->index = -1;
tmp_nctl->vcount = tctl[j].emu_ctl_count;/*1;*/
tmp_nctl->count = tctl[j].emu_ctl_count;/*1;*/
tmp_nctl->value[k] = tmp_octl->ctl_val;
tmp_nctl->min = tmp_octl->ctl_val_min;
tmp_nctl->max = tmp_octl->ctl_val_max;
tmp_nctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
}
idx = check_if_used(used_gpr, used_gpr_count, tmp_octl->ctl + 0x100);
if (idx >= 0)
used_gpr[idx].ld_gpr = EMU10K1_PREG_CTL(j, k);
transformed = 1;
break;
}
}
if (transformed)
break;
}
if (transformed)
continue;
/* not transformed */
tmp_nctl = &(np->ctl[tmp_cnt + tctl_count]);
strcpy(tmp_nctl->name, tmp_octl->ctl_name);
tmp_nctl->index = -1;
tmp_nctl->vcount = 1;
tmp_nctl->count = 1;
tmp_nctl->value[0] = tmp_octl->ctl_val;
tmp_nctl->min = tmp_octl->ctl_val_min;
tmp_nctl->max = tmp_octl->ctl_val_max;
tmp_nctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
idx = check_if_used(used_gpr, used_gpr_count, tmp_octl->ctl + 0x100);
if (idx >= 0)
used_gpr[idx].ld_gpr = EMU10K1_PREG_CTL(tmp_cnt + tctl_count, 0);
tmp_cnt++;
if (tmp_cnt > np->ctl_count) {
en = LD10K1_EF_ERR_TRANSFORM_CTL;
goto err;
}
}
if (tmp_cnt + tctl_count < np->ctl_count) {
en = LD10K1_EF_ERR_TRANSFORM_CTL;
goto err;
}
/* tram */
if ((en = liblo10k1_patch_set_tram_count(np, ep->tram_lookup_count + ep->tram_delay_count)) < 0)
goto err;
tmp_cnt = 0;
for (i = 0; i < ep->tram_lookup_count + ep->tram_delay_count; i++) {
if (i < ep->tram_lookup_count)
tram_tmp = &(ep->tram_lookups[i]);
else
tram_tmp = &(ep->tram_delays[i - ep->tram_lookup_count]);
tmp_cnt += tram_tmp->read_line_count + tram_tmp->write_line_count;
np->tram[i].grp_type = i < ep->tram_lookup_count ? TRAM_GRP_TABLE : TRAM_GRP_DELAY;
np->tram[i].grp_size = tram_tmp->size;
np->tram[i].grp_pos = TRAM_POS_AUTO;
}
/* tram acc */
if ((en = liblo10k1_patch_set_tram_acc_count(np, tmp_cnt)) < 0)
goto err;
tmp_cnt = 0;
for (i = 0; i < ep->tram_lookup_count + ep->tram_delay_count; i++) {
if (i < ep->tram_lookup_count)
tram_tmp = &(ep->tram_lookups[i]);
else
tram_tmp = &(ep->tram_delays[i - ep->tram_lookup_count]);
for (k = 0; k < 2; k++) {
for (j = 0; j < (k ? tram_tmp->write_line_count : tram_tmp->read_line_count); j++) {
if (k)
tram_line = &(tram_tmp->write_lines[j]);
else
tram_line = &(tram_tmp->read_lines[j]);
tram_nacc = &(np->tram_acc[tmp_cnt]);
tram_nacc->grp = i;
tram_nacc->acc_offset = tram_line->line_size;
tram_nacc->acc_type = k ? TRAM_ACC_WRITE : TRAM_ACC_READ;
idx = check_if_used(used_gpr, used_gpr_count, tram_line->line + 0x200);
if (idx >= 0)
used_gpr[idx].ld_gpr = EMU10K1_PREG_TRAM_DATA(tmp_cnt);
idx = check_if_used(used_gpr, used_gpr_count, tram_line->line + 0x300);
if (idx >= 0)
used_gpr[idx].ld_gpr = EMU10K1_PREG_TRAM_ADDR(tmp_cnt);
tmp_cnt++;
}
}
}
/* const and hw */
const_count = 0;
hw_count = 0;
for (i = 0; i < used_gpr_count; i++) {
gpr = used_gpr[i].gpr;
if (gpr < 0x40)
hw_count++;
else if (gpr < 0x56)
const_count++;
else if (gpr < 0x5C)
hw_count++;
}
/* const regs */
tmp_cnt = 0;
for (i = 0; i < ep->con_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->cons[i].sc + 0x100);
if (idx >= 0) {
used_gpr[idx].ld_gpr = EMU10K1_PREG_CONST(tmp_cnt);
tmp_cnt++;
}
}
/* consts */
if ((en = liblo10k1_patch_set_const_count(np, const_count + tmp_cnt)) < 0)
goto err;
const_count = tmp_cnt;
/* const regs - initilization */
tmp_cnt = 0;
for (i = 0; i < ep->con_count; i++) {
idx = check_if_used(used_gpr, used_gpr_count, ep->cons[i].sc + 0x100);
if (idx >= 0) {
np->consts[tmp_cnt].const_val = ep->cons[i].sc_val;
tmp_cnt++;
}
}
/* hw */
if ((en = liblo10k1_patch_set_hw_count(np, hw_count)) < 0)
goto err;
hw_count = 0;
for (i = 0; i < used_gpr_count; i++) {
gpr = used_gpr[i].gpr;
addconst = 0;
addhw = 0;
if (gpr < 0x40) {
/* fx */
addhw = 1;
if (gpr < 0x10)
val = EMU10K1_REG_FX(gpr);
else if (gpr < 0x20)
val = EMU10K1_REG_IN(gpr - 0x10);
else
val = EMU10K1_REG_OUT(gpr - 0x20);
} else {
switch (gpr) {
case 0x40:
addconst = 1; val = 0x00000000;
break;
case 0x41:
addconst = 1; val = 0x00000001;
break;
case 0x42:
addconst = 1; val = 0x00000002;
break;
case 0x43:
addconst = 1; val = 0x00000003;
break;
case 0x44:
addconst = 1; val = 0x00000004;
break;
case 0x45:
addconst = 1; val = 0x00000008;
break;
case 0x46:
addconst = 1; val = 0x00000010;
break;
case 0x47:
addconst = 1; val = 0x00000020;
break;
case 0x48:
addconst = 1; val = 0x00000100;
break;
case 0x49:
addconst = 1; val = 0x00010000;
break;
case 0x4A:
addconst = 1; val = 0x00080000;
break;
case 0x4B:
addconst = 1; val = 0x10000000;
break;
case 0x4C:
addconst = 1; val = 0x20000000;
break;
case 0x4D:
addconst = 1; val = 0x40000000;
break;
case 0x4E:
addconst = 1; val = 0x80000000;
break;
case 0x4F:
addconst = 1; val = 0x7FFFFFFF;
break;
case 0x50:
addconst = 1; val = 0xFFFFFFFF;
break;
case 0x51:
addconst = 1; val = 0xFFFFFFFE;
break;
case 0x52:
addconst = 1; val = 0xC0000000;
break;
case 0x53:
addconst = 1; val = 0x4F1BBCDC;
break;
case 0x54:
addconst = 1; val = 0x5A7EF9DB;
break;
case 0x55:
addconst = 1; val = 0x00100000;
break;
case 0x56:
addhw = 1; val = EMU10K1_NREG_HW_ACCUM;
break;
case 0x57:
addhw = 1; val = EMU10K1_NREG_HW_CCR;
break;
case 0x58:
addhw = 1; val = EMU10K1_NREG_HW_NOISE1;
break;
case 0x59:
addhw = 1; val = EMU10K1_NREG_HW_NOISE2;
break;
case 0x5A:
addhw = 1; val = EMU10K1_NREG_HW_IRQ;
break;
case 0x5B:
addhw = 1; val = EMU10K1_NREG_HW_DBAC;
break;
default:
if (gpr < 0x100) {
en = LD10K1_EF_ERR_TRANSFORM;
goto err;
}
break;
}
}
if (addhw) {
np->hws[hw_count].hw_val = val;
used_gpr[i].ld_gpr = EMU10K1_PREG_HW(hw_count);
hw_count++;
} else if (addconst) {
np->consts[const_count].const_val = val;
used_gpr[i].ld_gpr = EMU10K1_PREG_CONST(const_count);
const_count++;
}
}
/* instrs */
if ((en = liblo10k1_patch_set_instr_count(np, ep->instr_count)) < 0)
goto err;
for (i = 0; i < ep->instr_count; i++) {
np->instr[i].op_code = ep->instrs[i].op;
for (j = 0; j < 4; j++) {
gpr = ep->instrs[i].arg[j];
idx = check_if_used(used_gpr, used_gpr_count, gpr);
if (!used_gpr[idx].ld_gpr) {
en = LD10K1_EF_ERR_TRANSFORM;
goto err;
}
np->instr[i].arg[j] = used_gpr[idx].ld_gpr;
}
}
*lp = np;
return 0;
err:
if (np)
liblo10k1_patch_free(np);
return en;
}