mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-10-29 05:40:25 -04:00
435 lines
13 KiB
C
435 lines
13 KiB
C
/***************************************************************************
|
|
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"
|
|
#include"parse.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 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;
|
|
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{
|
|
list_add_tail(&(((struct tram *)sym)->tram) , &(tram_lookup[tmp].tram) );
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|