mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-10-29 05:40:25 -04:00
Added as10k1 tool (EMU10K1 FX8010 DSP assembler).
This commit is contained in:
parent
a4569af2bb
commit
f2d80b5b5d
28 changed files with 3523 additions and 0 deletions
438
as10k1/assemble.c
Normal file
438
as10k1/assemble.c
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
/***************************************************************************
|
||||
assemble.c - Assembles the parsed lines
|
||||
-------------------
|
||||
Date : May 24 2000
|
||||
Copyright : (C) 2000 by Daniel Bertrand
|
||||
Email : d.bertrand@ieee.ca
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include<string.h>
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#include"types.h"
|
||||
#include"proto.h"
|
||||
|
||||
extern int dbg_opt;
|
||||
extern FILE *listfile;
|
||||
extern char *listing;
|
||||
char type_strings[GPR_TYPE_EQUATE+1][20]={
|
||||
"Input",
|
||||
"Output",
|
||||
"Constant",
|
||||
"Static",
|
||||
"Dynamic",
|
||||
"Control",
|
||||
"Tram Data Reg",
|
||||
"Tram Address/Read",
|
||||
"Tram Address/Write",
|
||||
"Macro arg",
|
||||
"Equate"
|
||||
};
|
||||
|
||||
void op(int op, int z,int w,int x,int y)
|
||||
{
|
||||
int w0, w1;
|
||||
extern int dsp_code[DSP_CODE_SIZE];
|
||||
extern int ip;
|
||||
extern char op_codes[35][9];
|
||||
extern char listtemp[60];
|
||||
if (ip >= 0x200)
|
||||
as_exit("to many instructions");
|
||||
if (op >= 0x10 || op < 0x00)
|
||||
as_exit("illegal op code");
|
||||
|
||||
//check if gpr is valid, optional do additional modifications
|
||||
z=declared(z,1);
|
||||
declared(w,2);
|
||||
declared(x,3);
|
||||
declared(y,4);
|
||||
|
||||
if ( (dbg_opt & DBG_INSTR) !=0 )
|
||||
printf( "0x%03x\t%s(%d) \t0x%03x,0x%03x,0x%03x,0x%03x\n",2*ip,op_codes[op],op,z,w,x,y);
|
||||
if(listing)
|
||||
sprintf(listtemp, "0x%03x %-9s(%02d) 0x%03x,0x%03x,0x%03x,0x%03x",2*ip,op_codes[op],op,z,w,x,y);
|
||||
|
||||
w0 = (x << 10) | y;
|
||||
w1 = (op << 20) | (z << 10) | w;
|
||||
dsp_code[ip * 2] = w0;
|
||||
dsp_code[ip * 2 + 1] = w1;
|
||||
ip++;
|
||||
|
||||
}
|
||||
|
||||
int declared(int operand,int i){
|
||||
|
||||
struct sym *sym;
|
||||
extern struct list_head sym_head;
|
||||
struct list_head *entry;
|
||||
|
||||
|
||||
|
||||
if ((operand < 0x040)||(operand >= 0x400)){
|
||||
printf("** Assembler Error with Operand %d:0x%x\n",i,operand);
|
||||
as_exit("Operand has value out of range");
|
||||
}
|
||||
|
||||
if((operand < 0x400) && operand >= 0x100)
|
||||
{
|
||||
list_for_each(entry,&sym_head){
|
||||
sym=list_entry(entry,struct sym,list);
|
||||
if( (sym->data.address == operand ) && sym->type!=GPR_TYPE_EQUATE){
|
||||
if( ( sym->type==GPR_TYPE_CONSTANT) && (i==1) ){
|
||||
printf("** Assembler Error with Operand %d:0x%x\n",i,operand);
|
||||
as_exit("** Error: Destination register is a read-only constant");
|
||||
}
|
||||
|
||||
else if(sym->type!=GPR_TYPE_INPUT)
|
||||
return(operand);
|
||||
else
|
||||
return( i==1? operand + 1 : operand);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if(operand<0x100)
|
||||
return(operand);
|
||||
|
||||
printf("** Assembler Error with Operand %d:0x%x\n",i,operand);
|
||||
as_exit("Operand address is undeclared");
|
||||
return(0);
|
||||
}
|
||||
|
||||
//each operand will be something like : , sym1 + sym2 * sym3 ,
|
||||
//we will recursively decode each symbol and perform proper operations:
|
||||
int arg_decode(char *operand, int prev_val)
|
||||
{
|
||||
int value;
|
||||
char oper='0';
|
||||
|
||||
|
||||
//Nothing:
|
||||
if(operand==NULL)
|
||||
as_exit("Parse Error: missing operand(s)");
|
||||
|
||||
|
||||
if(*operand==','||*operand=='\n'||*operand=='\0')
|
||||
return(prev_val);
|
||||
|
||||
|
||||
//skip over leading blanks(if any):
|
||||
advance_over_whites(operand);
|
||||
|
||||
if(*operand==','||*operand=='\n' ||*operand=='\0')
|
||||
return(prev_val);
|
||||
|
||||
//get the operator:
|
||||
if(*operand=='+' || *operand=='-' || *operand=='/' || *operand== '*'){
|
||||
oper=*operand;
|
||||
operand++;
|
||||
}
|
||||
|
||||
//skip over any blanks after the oper
|
||||
advance_over_whites(operand);
|
||||
|
||||
//decode the symbol/value:
|
||||
value=arg_decode2(operand);
|
||||
|
||||
//advance to next symbol
|
||||
while( *operand!='+' && *operand!='-' && *operand!='/' && *operand!= '*' && *operand != '\0' &&*operand!=',' &&*operand!='\n')
|
||||
operand++;
|
||||
|
||||
switch (oper){
|
||||
|
||||
case '+':
|
||||
return(arg_decode(operand,prev_val+value));
|
||||
case '-':
|
||||
return(arg_decode(operand,prev_val-value));
|
||||
case '/':
|
||||
return(arg_decode(operand,prev_val/value));
|
||||
case '*':
|
||||
return(arg_decode(operand,prev_val*value));
|
||||
default:
|
||||
return(arg_decode(operand,value));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//this function does argument decoding
|
||||
int arg_decode2(char *operand)
|
||||
{
|
||||
extern int ip,ds_addr;
|
||||
extern unsigned int macro_depth;
|
||||
struct sym *sym;
|
||||
extern struct list_head sym_head;
|
||||
struct list_head *entry;
|
||||
//printf("operand:%s\n",operand);
|
||||
|
||||
|
||||
if(operand[0]=='.' &&isalpha(operand[1])){
|
||||
add_symbol(operand,GPR_TYPE_STATIC, ds_addr++, -(long)ip);
|
||||
return(ds_addr-1);
|
||||
}
|
||||
|
||||
|
||||
// Hex
|
||||
if((char)(*operand)=='$')
|
||||
return((int)strtol(operand+1,NULL,16));
|
||||
// Octal
|
||||
if((char)(*operand)=='@')
|
||||
return((int)strtol(operand+1,NULL,8));
|
||||
// Binary:
|
||||
if((char)(*operand)=='%')
|
||||
return((int)strtol(operand+1,NULL,2));
|
||||
// Decimal:
|
||||
if( (operand[0] >= '0' && operand[0] <='9') ||operand[0]=='-')
|
||||
return((int)strtol(operand,NULL,10));
|
||||
|
||||
|
||||
|
||||
//Symbol:
|
||||
list_for_each(entry,&sym_head){
|
||||
sym=list_entry(entry,struct sym,list);
|
||||
if(symcmp(sym->data.name,operand)==0){
|
||||
if(sym->type!=TYPE_MACRO_ARG)
|
||||
return(sym->data.address);
|
||||
else if(sym->data.value==(macro_depth))
|
||||
return(sym->data.address);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
printf("Parse error with operand: \"");
|
||||
while(!symend(operand))
|
||||
printf("%c",*(operand++));
|
||||
printf("\"\n");
|
||||
as_exit("Bad operand");
|
||||
|
||||
//printf("** Parse error with operand: \"%s\"\n",operand);
|
||||
as_exit("\"\nOperand isn't a defined symbol or value");
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
#define FACTOR 0x7fffffff
|
||||
#define SAMP_FREQ 48000
|
||||
//used by the DC operation to get a long int:
|
||||
long arg2long(char *operand){
|
||||
|
||||
|
||||
//Nothing:
|
||||
if(operand==NULL)
|
||||
as_exit("Parse Error: missing operand(s)");
|
||||
|
||||
advance(operand);
|
||||
|
||||
//Fractional ( -1 <= operand <= 1 )
|
||||
if(operand[0]=='#')
|
||||
return((long)(atof(operand+1)*FACTOR));
|
||||
// Time value
|
||||
if(operand[0]=='&')
|
||||
return((long)(atof(operand+1)*48000));
|
||||
// Hex:
|
||||
if((char)(*operand)=='$')
|
||||
return(strtoul(operand+1,NULL,16));
|
||||
// Binary:
|
||||
if((char)(*operand)=='%')
|
||||
return(strtoul(operand+1,NULL,2));
|
||||
// Octal:
|
||||
if((char)(*operand)=='@')
|
||||
return(strtoul(operand+1,NULL,8));
|
||||
// Decimal:
|
||||
if( (operand[0] >= '0' && operand[0] <='9') || operand[0]=='-' || operand[0]=='.'){
|
||||
if(atof(operand)<1 && atof(operand)>-1)
|
||||
return((long)(atof(operand)*FACTOR));
|
||||
else
|
||||
return(strtol(operand,NULL,10));
|
||||
}
|
||||
|
||||
|
||||
printf("Parse error with operand:\"%s\"\n",operand);
|
||||
// while(!symend(operand))
|
||||
// printf("%c",*operand);
|
||||
//printf("\"\n");
|
||||
as_exit("Bad operand");
|
||||
|
||||
return(0);
|
||||
}
|
||||
void update_symbol(char *name,u16 type,u16 address,u32 value){
|
||||
struct sym *sym;
|
||||
|
||||
|
||||
switch(type){
|
||||
|
||||
case TYPE_MACRO_ARG:
|
||||
|
||||
if( issymbol(name,&sym) == -1 ){
|
||||
add_symbol(name,type,address,value);
|
||||
return;
|
||||
}
|
||||
|
||||
if(sym->type!=TYPE_MACRO_ARG){
|
||||
printf("Error: with argument:%s",name);
|
||||
as_exit("Error:symbol is already defined");
|
||||
}
|
||||
sym->data.address=address;
|
||||
break;
|
||||
default:
|
||||
if( issymbol(name,&sym) == -1 ){
|
||||
add_symbol(name,type,address,value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void add_symbol(char *name, u16 type, u16 address, u32 value)
|
||||
{
|
||||
|
||||
extern int gpr_input_count,gpr_output_count,gpr_static_count,gpr_dynamic_count,gpr_control_count,gpr_constant_count;
|
||||
struct sym *sym;
|
||||
struct tram *tmp_ptr;
|
||||
extern struct list_head sym_head;
|
||||
extern struct delay tram_delay[MAX_TANK_ADDR];
|
||||
extern struct lookup tram_lookup[MAX_TANK_ADDR];
|
||||
int tmp;
|
||||
|
||||
|
||||
if(name==NULL)
|
||||
as_exit("Parse Error: This directive requires a label");
|
||||
|
||||
if(symcmp(name,NO_SYM)!=0 &&type== GPR_TYPE_CONSTANT){
|
||||
if(issymbol(name,&sym)==0){
|
||||
if(sym->data.value != value)
|
||||
as_exit("Error: Constant redeclared as another value");
|
||||
else
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(symcmp(name,NO_SYM)!=0 && type!=TYPE_MACRO_ARG)
|
||||
{
|
||||
if(issymbol(name,&sym)!=-1)
|
||||
as_exit("Parse Error: Symbol is already defined");
|
||||
if(ismacro(name)!=-1)
|
||||
as_exit("Parse Error: Symbol is already defined as a macro");
|
||||
if(isalpha(*name)==0 && name[0]!='.')
|
||||
as_exit("Parse Error: Symbol must start with a alpha character (a-z)");
|
||||
}
|
||||
|
||||
switch(type){
|
||||
case GPR_TYPE_CONTROL:
|
||||
sym=(struct sym *)malloc(sizeof(struct control));
|
||||
list_add_tail(&sym->list, &sym_head);
|
||||
break;
|
||||
case TYPE_TRAM_ADDR_READ:
|
||||
case TYPE_TRAM_ADDR_WRITE:
|
||||
sym=(struct sym *)malloc(sizeof(struct tram));
|
||||
list_add_tail(&sym->list, &sym_head);
|
||||
|
||||
//if ID is that of a delay:
|
||||
if((tmp=((struct sym * ) sym->list.prev)->data.value)>0xff){
|
||||
tmp=tmp-0x100;
|
||||
list_add_tail(&(((struct tram *)sym)->tram) , &(tram_delay[tmp].tram) );
|
||||
if(type== TYPE_TRAM_ADDR_READ)
|
||||
tram_delay[tmp].read++;
|
||||
else
|
||||
tram_delay[tmp].write++;
|
||||
}else{
|
||||
tmp_ptr=(struct tram *)sym;
|
||||
list_add_tail(&(((struct tram *)sym)->tram) , &(tram_lookup[tmp].tram) );
|
||||
tmp_ptr=(struct tram *)sym;
|
||||
if(type== TYPE_TRAM_ADDR_READ)
|
||||
tram_lookup[tmp].read++;
|
||||
else
|
||||
tram_lookup[tmp].write++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
sym=(struct sym *)malloc(sizeof(struct sym));
|
||||
list_add_tail(&sym->list, &sym_head);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
symcpy(sym->data.name,name);
|
||||
sym->data.address=address;
|
||||
sym->type=type;
|
||||
sym->data.value=value;
|
||||
//GPR debugging:
|
||||
if((dbg_opt&DBG_GPR) && type<=GPR_TYPE_CONTROL)
|
||||
printf("GPR: %-16s 0x%03x Value=0x%08x, Type: %s\n",name,address,value,type_strings[type] );
|
||||
|
||||
//tram debugging:
|
||||
else if((dbg_opt&DBG_TRAM && type == TYPE_TRAM_DATA))
|
||||
printf("TRAM Access: %-16s",name);
|
||||
else if((dbg_opt&DBG_TRAM && type == TYPE_TRAM_ADDR_WRITE))
|
||||
printf(", type: Write, using 0x%03x/0x%03x, offset:0x%07x",address,address-0x100,value );
|
||||
else if((dbg_opt&DBG_TRAM && type == TYPE_TRAM_ADDR_READ))
|
||||
printf(", type: Read, using 0x%03x/0x%03x, offset:0x%07x",address,address-0x100,value );
|
||||
//General Symbol debugging:
|
||||
else if((dbg_opt&DBG_SYM )){
|
||||
printf("symbol: %-16s 0x%03x Type: %s\n",name,address,type_strings[type]);
|
||||
}
|
||||
|
||||
|
||||
switch(type){
|
||||
case TYPE_MACRO_ARG:
|
||||
return;
|
||||
case GPR_TYPE_INPUT:
|
||||
gpr_input_count++;
|
||||
return;
|
||||
case GPR_TYPE_OUTPUT:
|
||||
gpr_output_count++;
|
||||
return;
|
||||
case GPR_TYPE_STATIC:
|
||||
gpr_static_count++;
|
||||
return;
|
||||
case GPR_TYPE_DYNAMIC:
|
||||
gpr_dynamic_count++;
|
||||
return;
|
||||
case GPR_TYPE_CONTROL:
|
||||
gpr_control_count++;
|
||||
return;
|
||||
case GPR_TYPE_CONSTANT:
|
||||
gpr_constant_count++;
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue