/***************************************************************************
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;
}
}