OpenCores
URL https://opencores.org/ocsvn/lxp32/lxp32/trunk

Subversion Repositories lxp32

[/] [lxp32/] [trunk/] [tools/] [src/] [lxp32asm/] [assembler.cpp] - Diff between revs 2 and 6

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 2 Rev 6
Line 28... Line 28...
 
 
        _line=0;
        _line=0;
        _state=Initial;
        _state=Initial;
        _currentFileName=filename;
        _currentFileName=filename;
        processFileRecursive(filename);
        processFileRecursive(filename);
 
 
// Examine symbol table
// Examine symbol table
        for(auto const &sym: _obj.symbols()) {
        for(auto const &sym: _obj.symbols()) {
                if(sym.second.type==LinkableObject::Unknown&&!sym.second.refs.empty()) {
                if(sym.second.type==LinkableObject::Unknown&&!sym.second.refs.empty()) {
                        std::ostringstream msg;
                        std::ostringstream msg;
                        msg<<"Undefined symbol \""+sym.first+"\"";
                        msg<<"Undefined symbol \""+sym.first+"\"";
                        msg<<" (referenced from "<<sym.second.refs[0].source;
                        msg<<" (referenced from "<<sym.second.refs[0].source;
                        msg<<":"<<sym.second.refs[0].line<<")";
                        msg<<":"<<sym.second.refs[0].line<<")";
                        throw std::runtime_error(msg.str());
                        throw std::runtime_error(msg.str());
                }
                }
        }
        }
 
 
 
        for(auto const &sym: _exportedSymbols) _obj.exportSymbol(sym);
}
}
 
 
void Assembler::processFileRecursive(const std::string &filename) {
void Assembler::processFileRecursive(const std::string &filename) {
        std::ifstream in(filename,std::ios_base::in);
        std::ifstream in(filename,std::ios_base::in);
        if(!in) throw std::runtime_error("Cannot open file \""+filename+"\"");
        if(!in) throw std::runtime_error("Cannot open file \""+filename+"\"");
Line 61... Line 64...
                expand(tokens);
                expand(tokens);
                elaborate(tokens);
                elaborate(tokens);
                _line++;
                _line++;
        }
        }
 
 
 
        if(_state!=Initial) throw std::runtime_error("Unexpected end of file");
 
 
        _line=savedLine;
        _line=savedLine;
        _state=savedState;
        _state=savedState;
        _currentFileName=savedFileName;
        _currentFileName=savedFileName;
 
 
        for(auto const &label: _currentLabels) {
        if(!_currentLabels.empty())
                _obj.addLocalSymbol(label,
                throw std::runtime_error("Symbol definition must be followed by an instruction or data definition statement");
                        static_cast<LinkableObject::Word>(_obj.codeSize()));
 
        }
 
 
 
        _currentLabels.clear();
 
}
}
 
 
void Assembler::addIncludeSearchDir(const std::string &dir) {
void Assembler::addIncludeSearchDir(const std::string &dir) {
        auto ndir=Utils::normalizeSeparators(dir);
        auto ndir=Utils::normalizeSeparators(dir);
        if(!ndir.empty()&&ndir.back()!='/') ndir.push_back('/');
        if(!ndir.empty()&&ndir.back()!='/') ndir.push_back('/');
Line 125... Line 126...
                                else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
                                else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
                        }
                        }
                        else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
                        else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
                        break;
                        break;
                case Word:
                case Word:
                        if(std::isalnum(ch)||ch=='_'||ch=='@') word+=ch;
                        if(std::isalnum(ch)||ch=='_'||ch=='@'||ch=='+'||ch=='-') word+=ch;
                        else {
                        else {
                                i--;
                                i--;
                                _state=Initial;
                                _state=Initial;
                                tokenList.push_back(std::move(word));
                                tokenList.push_back(std::move(word));
                        }
                        }
Line 204... Line 205...
void Assembler::expand(TokenList &list) {
void Assembler::expand(TokenList &list) {
        TokenList newlist;
        TokenList newlist;
// Perform macro substitution
// Perform macro substitution
        for(auto &token: list) {
        for(auto &token: list) {
                auto it=_macros.find(token);
                auto it=_macros.find(token);
                if(it==_macros.end()) newlist.push_back(std::move(token));
// Note: we don't expand a macro identifier in the #define statement
 
// since that would lead to counter-intuitive results
 
                if(it==_macros.end()||
 
                        (newlist.size()==1&&newlist[0]=="#define")||
 
                        (newlist.size()==3&&newlist[1]==":"&&newlist[2]=="#define"))
 
                                newlist.push_back(std::move(token));
                else for(auto const &replace: it->second) newlist.push_back(replace);
                else for(auto const &replace: it->second) newlist.push_back(replace);
        }
        }
        list=std::move(newlist);
        list=std::move(newlist);
}
}
 
 
Line 231... Line 237...
                LinkableObject::Word rva;
                LinkableObject::Word rva;
                if(list[0][0]=='.') rva=elaborateDataDefinition(list);
                if(list[0][0]=='.') rva=elaborateDataDefinition(list);
                else rva=elaborateInstruction(list);
                else rva=elaborateInstruction(list);
 
 
                for(auto const &label: _currentLabels) {
                for(auto const &label: _currentLabels) {
                        _obj.addLocalSymbol(label,rva);
                        _obj.addSymbol(label,rva);
                }
                }
                _currentLabels.clear();
                _currentLabels.clear();
        }
        }
}
}
 
 
void Assembler::elaborateDirective(TokenList &list) {
void Assembler::elaborateDirective(TokenList &list) {
        assert(!list.empty());
        assert(!list.empty());
 
 
        if(list[0]=="#define") {
        if(list[0]=="#define") {
                if(list.size()<3) throw std::runtime_error("Wrong number of tokens in the directive");
                if(list.size()<3)
                if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
                        throw std::runtime_error("Wrong number of tokens in the directive");
 
                if(_macros.find(list[1])!=_macros.end())
 
                        throw std::runtime_error("Macro \""+list[1]+"\" has been already defined");
 
                if(!validateIdentifier(list[1]))
 
                        throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
                _macros.emplace(list[1],TokenList(list.begin()+2,list.end()));
                _macros.emplace(list[1],TokenList(list.begin()+2,list.end()));
        }
        }
        else if(list[0]=="#extern") {
        else if(list[0]=="#export") {
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
                if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
                _obj.addExternalSymbol(list[1]);
                _exportedSymbols.push_back(list[1]);
 
        }
 
        else if(list[0]=="#import") {
 
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
 
                if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
 
                _obj.addImportedSymbol(list[1]);
        }
        }
        else if(list[0]=="#include") {
        else if(list[0]=="#include") {
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                auto filename=Utils::dequoteString(list[1]);
                auto filename=Utils::dequoteString(list[1]);
                if(Utils::isAbsolutePath(filename)) return processFileRecursive(filename);
                if(Utils::isAbsolutePath(filename)) return processFileRecursive(filename);
Line 283... Line 298...
 
 
        if(list[0]==".align") {
        if(list[0]==".align") {
                if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
                if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
                std::size_t align=4;
                std::size_t align=4;
                if(list.size()>1) align=static_cast<std::size_t>(numericLiteral(list[1]));
                if(list.size()>1) align=static_cast<std::size_t>(numericLiteral(list[1]));
 
                if(!Utils::isPowerOf2(align)) throw std::runtime_error("Alignment must be a power of 2");
 
                if(align<4) throw std::runtime_error("Alignment must be at least 4");
                rva=_obj.addPadding(align);
                rva=_obj.addPadding(align);
        }
        }
        else if(list[0]==".reserve") {
        else if(list[0]==".reserve") {
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
                else if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
                else if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
Line 349... Line 366...
        else if(list[0]=="divu") encodeDivu(list);
        else if(list[0]=="divu") encodeDivu(list);
        else if(list[0]=="hlt") encodeHlt(list);
        else if(list[0]=="hlt") encodeHlt(list);
        else if(list[0]=="jmp") encodeJmp(list);
        else if(list[0]=="jmp") encodeJmp(list);
        else if(list[0]=="iret") encodeIret(list);
        else if(list[0]=="iret") encodeIret(list);
        else if(list[0]=="lc") encodeLc(list);
        else if(list[0]=="lc") encodeLc(list);
 
        else if(list[0]=="lcs") encodeLcs(list);
        else if(list[0]=="lsb") encodeLsb(list);
        else if(list[0]=="lsb") encodeLsb(list);
        else if(list[0]=="lub") encodeLub(list);
        else if(list[0]=="lub") encodeLub(list);
        else if(list[0]=="lw") encodeLw(list);
        else if(list[0]=="lw") encodeLw(list);
        else if(list[0]=="mods") encodeMods(list);
        else if(list[0]=="mods") encodeMods(list);
        else if(list[0]=="modu") encodeModu(list);
        else if(list[0]=="modu") encodeModu(list);
        else if(list[0]=="mov") encodeMov(list);
        else if(list[0]=="mov") encodeMov(list);
        else if(list[0]=="mul") encodeMul(list);
        else if(list[0]=="mul") encodeMul(list);
 
        else if(list[0]=="neg") encodeNeg(list);
        else if(list[0]=="nop") encodeNop(list);
        else if(list[0]=="nop") encodeNop(list);
        else if(list[0]=="not") encodeNot(list);
        else if(list[0]=="not") encodeNot(list);
        else if(list[0]=="or") encodeOr(list);
        else if(list[0]=="or") encodeOr(list);
        else if(list[0]=="ret") encodeRet(list);
        else if(list[0]=="ret") encodeRet(list);
        else if(list[0]=="sb") encodeSb(list);
        else if(list[0]=="sb") encodeSb(list);
Line 454... Line 473...
                                a.type=Operand::Register;
                                a.type=Operand::Register;
                                a.reg=252;
                                a.reg=252;
                                arglist.push_back(std::move(a));
                                arglist.push_back(std::move(a));
                        }
                        }
                        else if(list[i].size()==3&&list[i].substr(0,2)=="iv"&&
                        else if(list[i].size()==3&&list[i].substr(0,2)=="iv"&&
                                std::isdigit(list[i][2])) // interrupt vector
                                list[i][2]>='0'&&list[i][2]<='7') // interrupt vector
                        {
                        {
                                a.type=Operand::Register;
                                a.type=Operand::Register;
                                a.reg=240+(list[i][2]-'0');
                                a.reg=240+(list[i][2]-'0');
                                arglist.push_back(std::move(a));
                                arglist.push_back(std::move(a));
                        }
                        }
Line 596... Line 615...
}
}
 
 
void Assembler::encodeDivs(const TokenList &list) {
void Assembler::encodeDivs(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("divs instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("divs instruction requires 3 operands");
        if(args[2].type==Operand::NumericLiteral&&args[2].i==0) {
 
                std::cerr<<currentFileName()<<":"<<line()<<": ";
 
                std::cerr<<"Warning: Division by zero"<<std::endl;
 
        }
 
 
 
        LinkableObject::Word w=0x54000000;
        LinkableObject::Word w=0x54000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        encodeRd2Operand(w,args[2]);
        encodeRd2Operand(w,args[2]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeDivu(const TokenList &list) {
void Assembler::encodeDivu(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("divu instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("divu instruction requires 3 operands");
        if(args[2].type==Operand::NumericLiteral&&args[2].i==0) {
 
                std::cerr<<currentFileName()<<":"<<line()<<": ";
 
                std::cerr<<"Warning: Division by zero"<<std::endl;
 
        }
 
 
 
        LinkableObject::Word w=0x50000000;
        LinkableObject::Word w=0x50000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        encodeRd2Operand(w,args[2]);
        encodeRd2Operand(w,args[2]);
        _obj.addWord(w);
        _obj.addWord(w);
Line 654... Line 663...
        LinkableObject::Word w=0x04000000;
        LinkableObject::Word w=0x04000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        _obj.addWord(w);
        _obj.addWord(w);
 
 
        if(args[1].type==Operand::Identifier) {
        if(args[1].type==Operand::Identifier) {
                auto symRva=_obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
                LinkableObject::Reference ref;
                _obj.addReference(args[1].str,currentFileName(),line(),symRva);
                ref.source=currentFileName();
 
                ref.line=line();
 
                ref.rva=_obj.addWord(0);
 
                ref.offset=args[1].i;
 
                ref.type=LinkableObject::Regular;
 
                _obj.addReference(args[1].str,ref);
        }
        }
        else if(args[1].type==Operand::NumericLiteral) {
        else if(args[1].type==Operand::NumericLiteral) {
                _obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
                _obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
        }
        }
        else throw std::runtime_error("\""+args[1].str+"\": bad argument");
        else throw std::runtime_error("\""+args[1].str+"\": bad argument");
}
}
 
 
 
void Assembler::encodeLcs(const TokenList &list) {
 
        auto args=getOperands(list);
 
        if(args.size()!=2) throw std::runtime_error("lcs instruction requires 2 operands");
 
 
 
        LinkableObject::Word w=0xA0000000;
 
        encodeDstOperand(w,args[0]);
 
 
 
        if(args[1].type==Operand::NumericLiteral) {
 
                if((args[1].i<-1048576||args[1].i>1048575)&&(args[1].i<0xFFF00000||args[1].i>0xFFFFFFFF))
 
                        throw std::runtime_error("\""+args[1].str+"\": out of range");
 
                auto c=static_cast<LinkableObject::Word>(args[1].i)&0x1FFFFF;
 
                w|=(c&0xFFFF);
 
                w|=((c<<8)&0x1F000000);
 
                _obj.addWord(w);
 
        }
 
        else if(args[1].type==Operand::Identifier) {
 
                LinkableObject::Reference ref;
 
                ref.source=currentFileName();
 
                ref.line=line();
 
                ref.rva=_obj.addWord(w);
 
                ref.offset=args[1].i;
 
                ref.type=LinkableObject::Short;
 
                _obj.addReference(args[1].str,ref);
 
        }
 
        else throw std::runtime_error("\""+args[1].str+"\": bad argument");
 
}
 
 
void Assembler::encodeLsb(const TokenList &list) {
void Assembler::encodeLsb(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("lsb instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("lsb instruction requires 2 operands");
        if(args[1].type!=Operand::Register) throw std::runtime_error("\""+args[1].str+"\": must be a register");
        if(args[1].type!=Operand::Register) throw std::runtime_error("\""+args[1].str+"\": must be a register");
        LinkableObject::Word w=0x2E000000;
        LinkableObject::Word w=0x2E000000;
Line 733... Line 774...
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        encodeRd2Operand(w,args[2]);
        encodeRd2Operand(w,args[2]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
 
void Assembler::encodeNeg(const TokenList &list) {
 
// Note: "neg" is not a real instruction, but an alias for "sub dst, 0, src"
 
        auto args=getOperands(list);
 
        if(args.size()!=2) throw std::runtime_error("neg instruction requires 2 operands");
 
        LinkableObject::Word w=0x44000000;
 
        encodeDstOperand(w,args[0]);
 
        encodeRd2Operand(w,args[1]);
 
        _obj.addWord(w);
 
}
 
 
void Assembler::encodeNop(const TokenList &list) {
void Assembler::encodeNop(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(!args.empty()) throw std::runtime_error("nop instruction doesn't take operands");
        if(!args.empty()) throw std::runtime_error("nop instruction doesn't take operands");
        _obj.addWord(0);
        _obj.addWord(0);
}
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.