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

Subversion Repositories lxp32

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

Only display areas with differences | Details | Blame | View Log

Rev 6 Rev 9
/*
/*
 * Copyright (c) 2016 by Alex I. Kuznetsov.
 * Copyright (c) 2016 by Alex I. Kuznetsov.
 *
 *
 * Part of the LXP32 CPU IP core.
 * Part of the LXP32 CPU IP core.
 *
 *
 * This module implements members of the Assembler class.
 * This module implements members of the Assembler class.
 */
 */
 
 
#include "assembler.h"
#include "assembler.h"
#include "utils.h"
#include "utils.h"
 
 
#include <iostream>
#include <iostream>
#include <fstream>
#include <fstream>
#include <sstream>
#include <sstream>
#include <stdexcept>
#include <stdexcept>
#include <utility>
#include <utility>
#include <limits>
#include <limits>
#include <type_traits>
#include <type_traits>
#include <cctype>
#include <cctype>
#include <cassert>
#include <cassert>
#include <cstdlib>
#include <cstdlib>
 
 
void Assembler::processFile(const std::string &filename) {
void Assembler::processFile(const std::string &filename) {
        auto nativePath=Utils::normalizeSeparators(filename);
        auto nativePath=Utils::normalizeSeparators(filename);
        auto pos=nativePath.find_last_of('/');
        auto pos=nativePath.find_last_of('/');
        if(pos!=std::string::npos) nativePath=filename.substr(pos+1);
        if(pos!=std::string::npos) nativePath=filename.substr(pos+1);
        _obj.setName(nativePath);
        _obj.setName(nativePath);
 
 
        _line=0;
        _line=0;
        _state=Initial;
        _state=Initial;
        _currentFileName=filename;
        _currentFileName=filename;
        processFileRecursive(filename);
        processFileRecursive(filename);
 
 
 
        if(!_currentLabels.empty())
 
                throw std::runtime_error("Symbol definition must be followed by an instruction or data definition statement");
 
 
 
        if(!_sectionEnabled.empty())
 
                throw std::runtime_error("#endif expected");
 
 
// 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);
        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+"\"");
 
 
// Process input file line-by-line
// Process input file line-by-line
        auto savedLine=_line;
        auto savedLine=_line;
        auto savedState=_state;
        auto savedState=_state;
        auto savedFileName=_currentFileName;
        auto savedFileName=_currentFileName;
 
 
        _line=1;
        _line=1;
        _state=Initial;
        _state=Initial;
        _currentFileName=filename;
        _currentFileName=filename;
 
 
        std::string line;
        std::string line;
        while(std::getline(in,line)) {
        while(std::getline(in,line)) {
                auto tokens=tokenize(line);
                auto tokens=tokenize(line);
                expand(tokens);
                expand(tokens);
                elaborate(tokens);
                elaborate(tokens);
                _line++;
                _line++;
        }
        }
 
 
        if(_state!=Initial) throw std::runtime_error("Unexpected end of file");
        if(_state!=Initial) throw std::runtime_error("Unexpected end of file");
 
 
        _line=savedLine;
        _line=savedLine;
        _state=savedState;
        _state=savedState;
        _currentFileName=savedFileName;
        _currentFileName=savedFileName;
 
 
        if(!_currentLabels.empty())
 
                throw std::runtime_error("Symbol definition must be followed by an instruction or data definition statement");
 
}
}
 
 
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('/');
        _includeSearchDirs.push_back(std::move(ndir));
        _includeSearchDirs.push_back(std::move(ndir));
}
}
 
 
int Assembler::line() const {
int Assembler::line() const {
        return _line;
        return _line;
}
}
 
 
std::string Assembler::currentFileName() const {
std::string Assembler::currentFileName() const {
        return _currentFileName;
        return _currentFileName;
}
}
 
 
LinkableObject &Assembler::object() {
LinkableObject &Assembler::object() {
        return _obj;
        return _obj;
}
}
 
 
const LinkableObject &Assembler::object() const {
const LinkableObject &Assembler::object() const {
        return _obj;
        return _obj;
}
}
 
 
Assembler::TokenList Assembler::tokenize(const std::string &str) {
Assembler::TokenList Assembler::tokenize(const std::string &str) {
        TokenList tokenList;
        TokenList tokenList;
        std::string word;
        std::string word;
        std::size_t i;
        std::size_t i;
        for(i=0;i<str.size();i++) {
        for(i=0;i<str.size();i++) {
                char ch=str[i];
                char ch=str[i];
                switch(_state) {
                switch(_state) {
                case Initial:
                case Initial:
                        if(ch==' '||ch=='\t'||ch=='\n'||ch=='\r') continue; // skip whitespace
                        if(ch==' '||ch=='\t'||ch=='\n'||ch=='\r') continue; // skip whitespace
                        else if(ch==','||ch==':') { // separator
                        else if(ch==','||ch==':') { // separator
                                tokenList.push_back(std::string(1,ch));
                                tokenList.push_back(std::string(1,ch));
                        }
                        }
                        else if(std::isalnum(ch)||ch=='.'||ch=='#'||ch=='_'||ch=='-'||ch=='+') {
                        else if(std::isalnum(ch)||ch=='.'||ch=='#'||ch=='_'||ch=='-'||ch=='+') {
                                word=std::string(1,ch);
                                word=std::string(1,ch);
                                _state=Word;
                                _state=Word;
                        }
                        }
                        else if(ch=='\"') {
                        else if(ch=='\"') {
                                word="\"";
                                word="\"";
                                _state=StringLiteral;
                                _state=StringLiteral;
                        }
                        }
                        else if(ch=='/') {
                        else if(ch=='/') {
                                if(++i>=str.size()) throw std::runtime_error("Unexpected end of line");
                                if(++i>=str.size()) throw std::runtime_error("Unexpected end of line");
                                ch=str[i];
                                ch=str[i];
                                if(ch=='/') i=str.size(); // skip the rest of the line
                                if(ch=='/') i=str.size(); // skip the rest of the line
                                else if(ch=='*') _state=BlockComment;
                                else if(ch=='*') _state=BlockComment;
                                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=='@'||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));
                        }
                        }
                        break;
                        break;
                case StringLiteral:
                case StringLiteral:
                        if(ch=='\\') {
                        if(ch=='\\') {
                                if(++i>=str.size()) throw std::runtime_error("Unexpected end of line");
                                if(++i>=str.size()) throw std::runtime_error("Unexpected end of line");
                                ch=str[i];
                                ch=str[i];
                                if(ch=='\\') word.push_back('\\');
                                if(ch=='\\') word.push_back('\\');
                                else if(ch=='\"') word.push_back('\"');
                                else if(ch=='\"') word.push_back('\"');
                                else if(ch=='\'') word.push_back('\'');
                                else if(ch=='\'') word.push_back('\'');
                                else if(ch=='t') word.push_back('\t');
                                else if(ch=='t') word.push_back('\t');
                                else if(ch=='n') word.push_back('\n');
                                else if(ch=='n') word.push_back('\n');
                                else if(ch=='r') word.push_back('\r');
                                else if(ch=='r') word.push_back('\r');
                                else if(ch=='x') { // hexadecimal sequence can be 1-2 digit long
                                else if(ch=='x') { // hexadecimal sequence can be 1-2 digit long
                                        std::string seq;
                                        std::string seq;
                                        if(i+1<str.size()&&Utils::ishexdigit(str[i+1])) seq+=str[i+1];
                                        if(i+1<str.size()&&Utils::ishexdigit(str[i+1])) seq+=str[i+1];
                                        if(i+2<str.size()&&Utils::ishexdigit(str[i+2])) seq+=str[i+2];
                                        if(i+2<str.size()&&Utils::ishexdigit(str[i+2])) seq+=str[i+2];
                                        if(seq.empty()) throw std::runtime_error("Ill-formed escape sequence");
                                        if(seq.empty()) throw std::runtime_error("Ill-formed escape sequence");
                                        try {
                                        try {
                                                word.push_back(static_cast<char>(std::stoul(seq,nullptr,16)));
                                                word.push_back(static_cast<char>(std::stoul(seq,nullptr,16)));
                                        }
                                        }
                                        catch(std::exception &) {
                                        catch(std::exception &) {
                                                throw std::runtime_error("Ill-formed escape sequence");
                                                throw std::runtime_error("Ill-formed escape sequence");
                                        }
                                        }
                                        i+=seq.size();
                                        i+=seq.size();
                                }
                                }
                                else if(Utils::isoctdigit(ch)) { // octal sequence can be 1-3 digit long
                                else if(Utils::isoctdigit(ch)) { // octal sequence can be 1-3 digit long
                                        std::string seq(1,ch);
                                        std::string seq(1,ch);
                                        if(i+1<str.size()&&Utils::isoctdigit(str[i+1])) seq+=str[i+1];
                                        if(i+1<str.size()&&Utils::isoctdigit(str[i+1])) seq+=str[i+1];
                                        if(i+2<str.size()&&Utils::isoctdigit(str[i+2])) seq+=str[i+2];
                                        if(i+2<str.size()&&Utils::isoctdigit(str[i+2])) seq+=str[i+2];
                                        unsigned long value;
                                        unsigned long value;
                                        try {
                                        try {
                                                value=std::stoul(seq,nullptr,8);
                                                value=std::stoul(seq,nullptr,8);
                                        }
                                        }
                                        catch(std::exception &) {
                                        catch(std::exception &) {
                                                throw std::runtime_error("Ill-formed escape sequence");
                                                throw std::runtime_error("Ill-formed escape sequence");
                                        }
                                        }
 
 
                                        if(value>255) throw std::runtime_error("Octal value is out of range");
                                        if(value>255) throw std::runtime_error("Octal value is out of range");
                                        word.push_back(static_cast<char>(value));
                                        word.push_back(static_cast<char>(value));
 
 
                                        i+=seq.size()-1;
                                        i+=seq.size()-1;
                                }
                                }
                                else throw std::runtime_error(std::string("Unknown escape sequence: \"\\")+ch+"\"");
                                else throw std::runtime_error(std::string("Unknown escape sequence: \"\\")+ch+"\"");
                        }
                        }
                        else if(ch=='\"') {
                        else if(ch=='\"') {
                                word.push_back('\"');
                                word.push_back('\"');
                                tokenList.push_back(std::move(word));
                                tokenList.push_back(std::move(word));
                                _state=Initial;
                                _state=Initial;
                        }
                        }
                        else word.push_back(ch);
                        else word.push_back(ch);
                        break;
                        break;
                case BlockComment:
                case BlockComment:
                        if(ch=='*') {
                        if(ch=='*') {
                                if(++i>=str.size()) break;
                                if(++i>=str.size()) break;
                                ch=str[i];
                                ch=str[i];
                                if(ch=='/') _state=Initial;
                                if(ch=='/') _state=Initial;
                                else i--;
                                else i--;
                        }
                        }
                        break;
                        break;
                }
                }
        }
        }
 
 
        if(_state==StringLiteral) throw std::runtime_error("Unexpected end of line");
        if(_state==StringLiteral) throw std::runtime_error("Unexpected end of line");
        if(_state==Word) tokenList.push_back(std::move(word)); // store last word
        if(_state==Word) tokenList.push_back(std::move(word)); // store last word
        if(_state!=BlockComment) _state=Initial; // reset state if not in block comment
        if(_state!=BlockComment) _state=Initial; // reset state if not in block comment
 
 
        return tokenList;
        return tokenList;
}
}
 
 
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);
// Note: we don't expand a macro identifier in the #define statement
                bool substitute=false;
// since that would lead to counter-intuitive results
                if(it!=_macros.end()) {
                if(it==_macros.end()||
                        substitute=true;
                        (newlist.size()==1&&newlist[0]=="#define")||
// Don't substitute macros for a second token in certain directives
                        (newlist.size()==3&&newlist[1]==":"&&newlist[2]=="#define"))
                        if(newlist.size()==1) {
                                newlist.push_back(std::move(token));
                                if(newlist[0]=="#define") substitute=false;
                else for(auto const &replace: it->second) newlist.push_back(replace);
                                else if(newlist[0]=="#ifdef") substitute=false;
 
                                else if(newlist[0]=="#ifndef") substitute=false;
 
                        }
 
                        else if(newlist.size()==3&&newlist[1]==":") {
 
                                if(newlist[2]=="#define") substitute=false;
 
                                else if(newlist[2]=="#ifdef") substitute=false;
 
                                else if(newlist[2]=="#ifndef") substitute=false;
 
                        }
 
                }
 
 
 
                if(substitute) {
 
                        for(auto const &replace: it->second) newlist.push_back(replace);
 
                }
 
                else newlist.push_back(std::move(token));
        }
        }
        list=std::move(newlist);
        list=std::move(newlist);
}
}
 
 
void Assembler::elaborate(TokenList &list) {
void Assembler::elaborate(TokenList &list) {
        if(list.empty()) return;
        if(list.empty()) return;
 
 
// Process label (if present)
// Process label (if present)
        if(list.size()>=2&&list[1]==":") {
        if(list.size()>=2&&list[1]==":") {
                if(!validateIdentifier(list[0]))
                if(!validateIdentifier(list[0]))
                        throw std::runtime_error("Ill-formed identifier: \""+list[0]+"\"");
                        throw std::runtime_error("Ill-formed identifier: \""+list[0]+"\"");
                _currentLabels.push_back(std::move(list[0]));
                if(isSectionEnabled()) _currentLabels.push_back(std::move(list[0]));
                list.erase(list.begin(),list.begin()+2);
                list.erase(list.begin(),list.begin()+2);
        }
        }
 
 
        if(list.empty()) return;
        if(list.empty()) return;
 
 
 
// If the section is disabled, we look only for #ifdef, #ifndef, #else or #endif
 
        if(!isSectionEnabled()&&list[0]!="#ifdef"&&list[0]!="#ifndef"&&
 
                list[0]!="#else"&&list[0]!="#endif") return;
 
 
// Process statement itself
// Process statement itself
        if(list[0][0]=='#') elaborateDirective(list);
        if(list[0][0]=='#') elaborateDirective(list);
        else {
        else {
                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.addSymbol(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)
                if(list.size()<2)
                        throw std::runtime_error("Wrong number of tokens in the directive");
                        throw std::runtime_error("Wrong number of tokens in the directive");
                if(_macros.find(list[1])!=_macros.end())
                if(_macros.find(list[1])!=_macros.end())
                        throw std::runtime_error("Macro \""+list[1]+"\" has been already defined");
                        throw std::runtime_error("Macro \""+list[1]+"\" has been already defined");
                if(!validateIdentifier(list[1]))
                if(!validateIdentifier(list[1]))
                        throw std::runtime_error("Ill-formed identifier: \""+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]=="#export") {
        else if(list[0]=="#export") {
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                if(list.size()!=2) throw 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]+"\"");
                _exportedSymbols.push_back(list[1]);
                _exportedSymbols.push_back(list[1]);
        }
        }
        else if(list[0]=="#import") {
        else if(list[0]=="#import") {
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                if(list.size()!=2) throw 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.addImportedSymbol(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) throw 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);
                else {
                else {
                        auto path=Utils::relativePath(currentFileName(),filename);
                        auto path=Utils::relativePath(currentFileName(),filename);
                        if(Utils::fileExists(path)) return processFileRecursive(path);
                        if(Utils::fileExists(path)) return processFileRecursive(path);
                        else {
                        else {
                                for(auto const &dir: _includeSearchDirs) {
                                for(auto const &dir: _includeSearchDirs) {
                                        path=Utils::nativeSeparators(dir+filename);
                                        path=Utils::nativeSeparators(dir+filename);
                                        if(Utils::fileExists(path)) return processFileRecursive(path);
                                        if(Utils::fileExists(path)) return processFileRecursive(path);
                                }
                                }
                        }
                        }
                }
                }
                throw std::runtime_error("Cannot locate include file \""+filename+"\"");
                throw std::runtime_error("Cannot locate include file \""+filename+"\"");
        }
        }
        else if(list[0]=="#message") {
        else if(list[0]=="#message") {
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
                if(list.size()!=2) throw std::runtime_error("Wrong number of tokens in the directive");
                auto msg=Utils::dequoteString(list[1]);
                auto msg=Utils::dequoteString(list[1]);
                std::cout<<currentFileName()<<":"<<line()<<": "<<msg<<std::endl;
                std::cout<<currentFileName()<<":"<<line()<<": "<<msg<<std::endl;
        }
        }
 
        else if(list[0]=="#error") {
 
                if(list.size()<2) throw std::runtime_error("#error directive encountered");
 
                auto msg=Utils::dequoteString(list[1]);
 
                throw std::runtime_error(msg);
 
        }
 
        else if(list[0]=="#ifdef") {
 
                if(list.size()!=2) throw std::runtime_error("Wrong number of tokens in the directive");
 
                if(_macros.find(list[1])!=_macros.end()) _sectionEnabled.push_back(true);
 
                else _sectionEnabled.push_back(false);
 
        }
 
        else if(list[0]=="#ifndef") {
 
                if(list.size()!=2) throw std::runtime_error("Wrong number of tokens in the directive");
 
                if(_macros.find(list[1])!=_macros.end()) _sectionEnabled.push_back(false);
 
                else _sectionEnabled.push_back(true);
 
        }
 
        else if(list[0]=="#else") {
 
                if(list.size()!=1) throw std::runtime_error("Wrong number of tokens in the directive");
 
                if(_sectionEnabled.empty()) throw std::runtime_error("Unexpected #else");
 
                _sectionEnabled.back()=!_sectionEnabled.back();
 
        }
 
        else if(list[0]=="#endif") {
 
                if(list.size()!=1) throw std::runtime_error("Wrong number of tokens in the directive");
 
                if(_sectionEnabled.empty()) throw std::runtime_error("Unexpected #endif");
 
                _sectionEnabled.pop_back();
 
        }
        else throw std::runtime_error("Unrecognized directive: \""+list[0]+"\"");
        else throw std::runtime_error("Unrecognized directive: \""+list[0]+"\"");
}
}
 
 
LinkableObject::Word Assembler::elaborateDataDefinition(TokenList &list) {
LinkableObject::Word Assembler::elaborateDataDefinition(TokenList &list) {
        assert(!list.empty());
        assert(!list.empty());
 
 
        LinkableObject::Word rva=0;
        LinkableObject::Word rva=0;
 
 
        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(!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");
                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]+"\"");
                auto n=static_cast<std::size_t>(numericLiteral(list[1]));
                auto n=static_cast<std::size_t>(numericLiteral(list[1]));
                rva=_obj.addZeros(n);
                rva=_obj.addZeros(n);
        }
        }
        else if(list[0]==".word") {
        else if(list[0]==".word") {
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
                for(std::size_t i=1;i<list.size();i++) {
                for(std::size_t i=1;i<list.size();i++) {
                        if(i%2!=0) {
                        if(i%2!=0) {
                                auto w=static_cast<LinkableObject::Word>(numericLiteral(list[i]));
                                auto w=static_cast<LinkableObject::Word>(numericLiteral(list[i]));
                                auto r=_obj.addWord(w);
                                auto r=_obj.addWord(w);
                                if(i==1) rva=r;
                                if(i==1) rva=r;
                        }
                        }
                        else {
                        else {
                                if(list[i]!=",") throw std::runtime_error("Comma expected");
                                if(list[i]!=",") throw std::runtime_error("Comma expected");
                                if(i+1==list.size()) throw std::runtime_error("Unexpected end of statement");
                                if(i+1==list.size()) throw std::runtime_error("Unexpected end of statement");
                        }
                        }
                }
                }
        }
        }
        else if(list[0]==".byte") {
        else if(list[0]==".byte") {
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
                for(std::size_t i=1;i<list.size();i++) {
                for(std::size_t i=1;i<list.size();i++) {
                        if(i%2!=0) {
                        if(i%2!=0) {
                                if(list[i].at(0)=='\"') { // string literal
                                if(list[i].at(0)=='\"') { // string literal
                                        auto bytes=Utils::dequoteString(list[i]);
                                        auto bytes=Utils::dequoteString(list[i]);
                                        auto r=_obj.addBytes(reinterpret_cast<const LinkableObject::Byte*>
                                        auto r=_obj.addBytes(reinterpret_cast<const LinkableObject::Byte*>
                                                (bytes.c_str()),bytes.size());
                                                (bytes.c_str()),bytes.size());
                                        if(i==1) rva=r;
                                        if(i==1) rva=r;
                                }
                                }
                                else {
                                else {
                                        auto n=numericLiteral(list[i]);
                                        auto n=numericLiteral(list[i]);
 
 
                                        if(n>255||n<-128) throw std::runtime_error("\""+list[i]+"\": out of range");
                                        if(n>255||n<-128) throw std::runtime_error("\""+list[i]+"\": out of range");
 
 
                                        auto b=static_cast<LinkableObject::Byte>(n);
                                        auto b=static_cast<LinkableObject::Byte>(n);
                                        auto r=_obj.addByte(b);
                                        auto r=_obj.addByte(b);
                                        if(i==1) rva=r;
                                        if(i==1) rva=r;
                                }
                                }
                        }
                        }
                        else {
                        else {
                                if(list[i]!=",") throw std::runtime_error("Comma expected");
                                if(list[i]!=",") throw std::runtime_error("Comma expected");
                                if(i+1==list.size()) throw std::runtime_error("Unexpected end of statement");
                                if(i+1==list.size()) throw std::runtime_error("Unexpected end of statement");
                        }
                        }
                }
                }
        }
        }
        else throw std::runtime_error("Unrecognized statement: \""+list[0]+"\"");
        else throw std::runtime_error("Unrecognized statement: \""+list[0]+"\"");
 
 
        return rva;
        return rva;
}
}
 
 
LinkableObject::Word Assembler::elaborateInstruction(TokenList &list) {
LinkableObject::Word Assembler::elaborateInstruction(TokenList &list) {
        assert(!list.empty());
        assert(!list.empty());
        auto rva=_obj.addPadding();
        auto rva=_obj.addPadding();
        if(list[0]=="add") encodeAdd(list);
        if(list[0]=="add") encodeAdd(list);
        else if(list[0]=="and") encodeAnd(list);
        else if(list[0]=="and") encodeAnd(list);
        else if(list[0]=="call") encodeCall(list);
        else if(list[0]=="call") encodeCall(list);
        else if(list[0].substr(0,4)=="cjmp") encodeCjmpxx(list);
        else if(list[0].substr(0,4)=="cjmp") encodeCjmpxx(list);
        else if(list[0]=="divs") encodeDivs(list);
        else if(list[0]=="divs") encodeDivs(list);
        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]=="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]=="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);
        else if(list[0]=="sl") encodeSl(list);
        else if(list[0]=="sl") encodeSl(list);
        else if(list[0]=="srs") encodeSrs(list);
        else if(list[0]=="srs") encodeSrs(list);
        else if(list[0]=="sru") encodeSru(list);
        else if(list[0]=="sru") encodeSru(list);
        else if(list[0]=="sub") encodeSub(list);
        else if(list[0]=="sub") encodeSub(list);
        else if(list[0]=="sw") encodeSw(list);
        else if(list[0]=="sw") encodeSw(list);
        else if(list[0]=="xor") encodeXor(list);
        else if(list[0]=="xor") encodeXor(list);
        else throw std::runtime_error("Unrecognized instruction: \""+list[0]+"\"");
        else throw std::runtime_error("Unrecognized instruction: \""+list[0]+"\"");
        return rva;
        return rva;
}
}
 
 
 
bool Assembler::isSectionEnabled() const {
 
        if(_sectionEnabled.empty()) return true;
 
        bool enabled=true;
 
        for(auto b: _sectionEnabled) enabled=enabled&&b;
 
        return enabled;
 
}
 
 
bool Assembler::validateIdentifier(const std::string &str) {
bool Assembler::validateIdentifier(const std::string &str) {
/*
/*
 * Valid identifier must satisfy the following requirements:
 * Valid identifier must satisfy the following requirements:
 *  1. Must not be empty
 *  1. Must not be empty
 *  2. The first character must be either alphabetic or an underscore
 *  2. The first character must be either alphabetic or an underscore
 *  3. Subsequent characters must be either alphanumeric or underscores
 *  3. Subsequent characters must be either alphanumeric or underscores
 */
 */
        if(str.empty()) return false;
        if(str.empty()) return false;
        for(std::size_t i=0;i<str.size();i++) {
        for(std::size_t i=0;i<str.size();i++) {
                char ch=str[i];
                char ch=str[i];
                if(i==0) {
                if(i==0) {
                        if(!std::isalpha(ch)&&ch!='_') return false;
                        if(!std::isalpha(ch)&&ch!='_') return false;
                }
                }
                else {
                else {
                        if(!std::isalnum(ch)&&ch!='_') return false;
                        if(!std::isalnum(ch)&&ch!='_') return false;
                }
                }
        }
        }
        return true;
        return true;
}
}
 
 
Assembler::Integer Assembler::numericLiteral(const std::string &str) {
Assembler::Integer Assembler::numericLiteral(const std::string &str) {
        std::size_t pos;
        std::size_t pos;
        Integer i;
        Integer i;
        try {
        try {
                i=std::stoll(str,&pos,0);
                i=std::stoll(str,&pos,0);
        }
        }
        catch(std::exception &) {
        catch(std::exception &) {
                throw std::runtime_error("Ill-formed numeric literal: \""+str+"\"");
                throw std::runtime_error("Ill-formed numeric literal: \""+str+"\"");
        }
        }
        if(pos<str.size()) throw std::runtime_error("Ill-formed numeric literal: \""+str+"\"");
        if(pos<str.size()) throw std::runtime_error("Ill-formed numeric literal: \""+str+"\"");
 
 
        typedef std::make_signed<LinkableObject::Word>::type SignedWord;
        typedef std::make_signed<LinkableObject::Word>::type SignedWord;
 
 
        if(i>static_cast<Integer>(std::numeric_limits<LinkableObject::Word>::max())||
        if(i>static_cast<Integer>(std::numeric_limits<LinkableObject::Word>::max())||
                i<static_cast<Integer>(std::numeric_limits<SignedWord>::min()))
                i<static_cast<Integer>(std::numeric_limits<SignedWord>::min()))
                        throw std::runtime_error("\""+str+"\": out of range");
                        throw std::runtime_error("\""+str+"\": out of range");
 
 
        return i;
        return i;
}
}
 
 
std::vector<Assembler::Operand> Assembler::getOperands(const TokenList &list) {
std::vector<Assembler::Operand> Assembler::getOperands(const TokenList &list) {
        std::vector<Operand> arglist;
        std::vector<Operand> arglist;
        for(std::size_t i=1;i<list.size();i++) {
        for(std::size_t i=1;i<list.size();i++) {
                if(i%2!=0) {
                if(i%2!=0) {
                        Operand a;
                        Operand a;
                        a.str=list[i];
                        a.str=list[i];
 
 
                        if(!list[i].empty()&&list[i][0]=='r') {
                        if(!list[i].empty()&&list[i][0]=='r') {
// Is argument a register?
// Is argument a register?
                                char *endptr;
                                char *endptr;
                                auto regstr=list[i].substr(1);
                                auto regstr=list[i].substr(1);
                                auto reg=std::strtol(regstr.c_str(),&endptr,10);
                                auto reg=std::strtol(regstr.c_str(),&endptr,10);
 
 
                                if(!*endptr&&reg>=0&&reg<=255) {
                                if(!*endptr&&reg>=0&&reg<=255) {
                                        a.type=Operand::Register;
                                        a.type=Operand::Register;
                                        a.reg=static_cast<std::uint8_t>(reg);
                                        a.reg=static_cast<std::uint8_t>(reg);
                                        arglist.push_back(std::move(a));
                                        arglist.push_back(std::move(a));
                                        continue;
                                        continue;
                                }
                                }
                        }
                        }
 
 
// Try alternative register names
// Try alternative register names
                        if(list[i]=="sp") { // stack pointer
                        if(list[i]=="sp") { // stack pointer
                                a.type=Operand::Register;
                                a.type=Operand::Register;
                                a.reg=255;
                                a.reg=255;
                                arglist.push_back(std::move(a));
                                arglist.push_back(std::move(a));
                        }
                        }
                        else if(list[i]=="rp") { // return pointer
                        else if(list[i]=="rp") { // return pointer
                                a.type=Operand::Register;
                                a.type=Operand::Register;
                                a.reg=254;
                                a.reg=254;
                                arglist.push_back(std::move(a));
                                arglist.push_back(std::move(a));
                        }
                        }
                        else if(list[i]=="irp") { // interrupt return pointer
                        else if(list[i]=="irp") { // interrupt return pointer
                                a.type=Operand::Register;
                                a.type=Operand::Register;
                                a.reg=253;
                                a.reg=253;
                                arglist.push_back(std::move(a));
                                arglist.push_back(std::move(a));
                        }
                        }
                        else if(list[i]=="cr") { // control register
                        else if(list[i]=="cr") { // control register
                                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"&&
                                list[i][2]>='0'&&list[i][2]<='7') // 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));
                        }
                        }
                        else if(validateIdentifier(list[i])) {
                        else if(validateIdentifier(list[i])) {
// Is argument an identifier?
// Is argument an identifier?
                                a.type=Operand::Identifier;
                                a.type=Operand::Identifier;
                                arglist.push_back(std::move(a));
                                arglist.push_back(std::move(a));
                        }
                        }
                        else {
                        else {
                                auto atpos=list[i].find_first_of('@');
                                auto atpos=list[i].find_first_of('@');
                                if(atpos!=std::string::npos) {
                                if(atpos!=std::string::npos) {
// Identifier with an offset?
// Identifier with an offset?
                                        a.type=Operand::Identifier;
                                        a.type=Operand::Identifier;
                                        a.str=list[i].substr(0,atpos);
                                        a.str=list[i].substr(0,atpos);
                                        if(!validateIdentifier(a.str)) throw std::runtime_error("Ill-formed identifier");
                                        if(!validateIdentifier(a.str)) throw std::runtime_error("Ill-formed identifier");
                                        a.i=numericLiteral(list[i].substr(atpos+1));
                                        a.i=numericLiteral(list[i].substr(atpos+1));
                                        arglist.push_back(std::move(a));
                                        arglist.push_back(std::move(a));
                                }
                                }
                                else {
                                else {
// Numeric literal?
// Numeric literal?
                                        a.type=Operand::NumericLiteral;
                                        a.type=Operand::NumericLiteral;
                                        a.i=numericLiteral(list[i]);
                                        a.i=numericLiteral(list[i]);
                                        arglist.push_back(std::move(a));
                                        arglist.push_back(std::move(a));
                                }
                                }
                        }
                        }
                }
                }
                else {
                else {
                        if(list[i]!=",") throw std::runtime_error("Comma expected");
                        if(list[i]!=",") throw std::runtime_error("Comma expected");
                        if(i+1==list.size()) throw std::runtime_error("Unexpected end of line");
                        if(i+1==list.size()) throw std::runtime_error("Unexpected end of line");
                }
                }
        }
        }
        return arglist;
        return arglist;
}
}
 
 
/*
/*
 * Member functions to encode LXP32 instructions
 * Member functions to encode LXP32 instructions
 */
 */
 
 
void Assembler::encodeDstOperand(LinkableObject::Word &word,const Operand &arg) {
void Assembler::encodeDstOperand(LinkableObject::Word &word,const Operand &arg) {
        if(arg.type!=Operand::Register)
        if(arg.type!=Operand::Register)
                throw std::runtime_error("\""+arg.str+"\": must be a register");
                throw std::runtime_error("\""+arg.str+"\": must be a register");
        word|=arg.reg<<16;
        word|=arg.reg<<16;
}
}
 
 
void Assembler::encodeRd1Operand(LinkableObject::Word &word,const Operand &arg) {
void Assembler::encodeRd1Operand(LinkableObject::Word &word,const Operand &arg) {
        if(arg.type==Operand::Register) {
        if(arg.type==Operand::Register) {
                word|=0x02000000;
                word|=0x02000000;
                word|=arg.reg<<8;
                word|=arg.reg<<8;
        }
        }
        else if(arg.type==Operand::NumericLiteral) {
        else if(arg.type==Operand::NumericLiteral) {
                if((arg.i<-128||arg.i>127)&&(arg.i<0xFFFFFF80||arg.i>0xFFFFFFFF))
                if((arg.i<-128||arg.i>127)&&(arg.i<0xFFFFFF80||arg.i>0xFFFFFFFF))
                        throw std::runtime_error("\""+arg.str+"\": out of range");
                        throw std::runtime_error("\""+arg.str+"\": out of range");
                auto b=static_cast<LinkableObject::Byte>(arg.i);
                auto b=static_cast<LinkableObject::Byte>(arg.i);
                word|=b<<8;
                word|=b<<8;
        }
        }
        else throw std::runtime_error("\""+arg.str+"\": bad argument");
        else throw std::runtime_error("\""+arg.str+"\": bad argument");
}
}
 
 
void Assembler::encodeRd2Operand(LinkableObject::Word &word,const Operand &arg) {
void Assembler::encodeRd2Operand(LinkableObject::Word &word,const Operand &arg) {
        if(arg.type==Operand::Register) {
        if(arg.type==Operand::Register) {
                word|=0x01000000;
                word|=0x01000000;
                word|=arg.reg;
                word|=arg.reg;
        }
        }
        else if(arg.type==Operand::NumericLiteral) {
        else if(arg.type==Operand::NumericLiteral) {
                if((arg.i<-128||arg.i>127)&&(arg.i<0xFFFFFF80||arg.i>0xFFFFFFFF))
                if((arg.i<-128||arg.i>127)&&(arg.i<0xFFFFFF80||arg.i>0xFFFFFFFF))
                        throw std::runtime_error("\""+arg.str+"\": out of range");
                        throw std::runtime_error("\""+arg.str+"\": out of range");
                auto b=static_cast<LinkableObject::Byte>(arg.i);
                auto b=static_cast<LinkableObject::Byte>(arg.i);
                word|=b;
                word|=b;
        }
        }
        else throw std::runtime_error("\""+arg.str+"\": bad argument");
        else throw std::runtime_error("\""+arg.str+"\": bad argument");
}
}
 
 
void Assembler::encodeAdd(const TokenList &list) {
void Assembler::encodeAdd(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("add instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("add instruction requires 3 operands");
        LinkableObject::Word w=0x40000000;
        LinkableObject::Word w=0x40000000;
        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::encodeAnd(const TokenList &list) {
void Assembler::encodeAnd(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("and instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("and instruction requires 3 operands");
        LinkableObject::Word w=0x60000000;
        LinkableObject::Word w=0x60000000;
        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::encodeCall(const TokenList &list) {
void Assembler::encodeCall(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=1) throw std::runtime_error("call instruction requires 1 operand");
        if(args.size()!=1) throw std::runtime_error("call instruction requires 1 operand");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        LinkableObject::Word w=0x86FE0000;
        LinkableObject::Word w=0x86FE0000;
        encodeRd1Operand(w,args[0]);
        encodeRd1Operand(w,args[0]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeCjmpxx(const TokenList &list) {
void Assembler::encodeCjmpxx(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("cjmpxx instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("cjmpxx instruction requires 3 operands");
 
 
        LinkableObject::Word w;
        LinkableObject::Word w;
        bool reverse=false;
        bool reverse=false;
/*
/*
 * Note: cjmpul, cjmpule, cjmpsl and cjmpsle don't have distinct opcodes;
 * Note: cjmpul, cjmpule, cjmpsl and cjmpsle don't have distinct opcodes;
 * instead, they are aliases for respective "g" or "ge" instructions
 * instead, they are aliases for respective "g" or "ge" instructions
 * with reversed operand order.
 * with reversed operand order.
 */
 */
        if(list[0]=="cjmpe") w=0xE0000000;
        if(list[0]=="cjmpe") w=0xE0000000;
        else if(list[0]=="cjmpne") w=0xD0000000;
        else if(list[0]=="cjmpne") w=0xD0000000;
        else if(list[0]=="cjmpug"||list[0]=="cjmpul") w=0xC8000000;
        else if(list[0]=="cjmpug"||list[0]=="cjmpul") w=0xC8000000;
        else if(list[0]=="cjmpuge"||list[0]=="cjmpule") w=0xE8000000;
        else if(list[0]=="cjmpuge"||list[0]=="cjmpule") w=0xE8000000;
        else if(list[0]=="cjmpsg"||list[0]=="cjmpsl") w=0xC4000000;
        else if(list[0]=="cjmpsg"||list[0]=="cjmpsl") w=0xC4000000;
        else if(list[0]=="cjmpsge"||list[0]=="cjmpsle") w=0xE4000000;
        else if(list[0]=="cjmpsge"||list[0]=="cjmpsle") w=0xE4000000;
        else throw std::runtime_error("Unrecognized instruction: \""+list[0]+"\"");
        else throw std::runtime_error("Unrecognized instruction: \""+list[0]+"\"");
 
 
        if(list[0]=="cjmpul"||list[0]=="cjmpule"||
        if(list[0]=="cjmpul"||list[0]=="cjmpule"||
                list[0]=="cjmpsl"||list[0]=="cjmpsle") reverse=true;
                list[0]=="cjmpsl"||list[0]=="cjmpsle") reverse=true;
 
 
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
 
 
        if(!reverse) {
        if(!reverse) {
                encodeRd1Operand(w,args[1]);
                encodeRd1Operand(w,args[1]);
                encodeRd2Operand(w,args[2]);
                encodeRd2Operand(w,args[2]);
        }
        }
        else {
        else {
                encodeRd1Operand(w,args[2]);
                encodeRd1Operand(w,args[2]);
                encodeRd2Operand(w,args[1]);
                encodeRd2Operand(w,args[1]);
        }
        }
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
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");
        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");
        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);
}
}
 
 
void Assembler::encodeHlt(const TokenList &list) {
void Assembler::encodeHlt(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(!args.empty()) throw std::runtime_error("hlt instruction doesn't take operands");
        if(!args.empty()) throw std::runtime_error("hlt instruction doesn't take operands");
        _obj.addWord(0x08000000);
        _obj.addWord(0x08000000);
}
}
 
 
void Assembler::encodeJmp(const TokenList &list) {
void Assembler::encodeJmp(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=1) throw std::runtime_error("jmp instruction requires 1 operand");
        if(args.size()!=1) throw std::runtime_error("jmp instruction requires 1 operand");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        LinkableObject::Word w=0x82000000;
        LinkableObject::Word w=0x82000000;
        encodeRd1Operand(w,args[0]);
        encodeRd1Operand(w,args[0]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeIret(const TokenList &list) {
void Assembler::encodeIret(const TokenList &list) {
// Note: "iret" is not a real instruction, but an alias for "jmp irp"
// Note: "iret" is not a real instruction, but an alias for "jmp irp"
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(!args.empty()) throw std::runtime_error("iret instruction doesn't take operands");
        if(!args.empty()) throw std::runtime_error("iret instruction doesn't take operands");
        _obj.addWord(0x8200FD00);
        _obj.addWord(0x8200FD00);
}
}
 
 
void Assembler::encodeLc(const TokenList &list) {
void Assembler::encodeLc(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("lc instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("lc instruction requires 2 operands");
 
 
        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) {
                LinkableObject::Reference ref;
                LinkableObject::Reference ref;
                ref.source=currentFileName();
                ref.source=currentFileName();
                ref.line=line();
                ref.line=line();
                ref.rva=_obj.addWord(0);
                ref.rva=_obj.addWord(0);
                ref.offset=args[1].i;
                ref.offset=args[1].i;
                ref.type=LinkableObject::Regular;
                ref.type=LinkableObject::Regular;
                _obj.addReference(args[1].str,ref);
                _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) {
void Assembler::encodeLcs(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("lcs instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("lcs instruction requires 2 operands");
 
 
        LinkableObject::Word w=0xA0000000;
        LinkableObject::Word w=0xA0000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
 
 
        if(args[1].type==Operand::NumericLiteral) {
        if(args[1].type==Operand::NumericLiteral) {
                if((args[1].i<-1048576||args[1].i>1048575)&&(args[1].i<0xFFF00000||args[1].i>0xFFFFFFFF))
                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");
                        throw std::runtime_error("\""+args[1].str+"\": out of range");
                auto c=static_cast<LinkableObject::Word>(args[1].i)&0x1FFFFF;
                auto c=static_cast<LinkableObject::Word>(args[1].i)&0x1FFFFF;
                w|=(c&0xFFFF);
                w|=(c&0xFFFF);
                w|=((c<<8)&0x1F000000);
                w|=((c<<8)&0x1F000000);
                _obj.addWord(w);
                _obj.addWord(w);
        }
        }
        else if(args[1].type==Operand::Identifier) {
        else if(args[1].type==Operand::Identifier) {
                LinkableObject::Reference ref;
                LinkableObject::Reference ref;
                ref.source=currentFileName();
                ref.source=currentFileName();
                ref.line=line();
                ref.line=line();
                ref.rva=_obj.addWord(w);
                ref.rva=_obj.addWord(w);
                ref.offset=args[1].i;
                ref.offset=args[1].i;
                ref.type=LinkableObject::Short;
                ref.type=LinkableObject::Short;
                _obj.addReference(args[1].str,ref);
                _obj.addReference(args[1].str,ref);
        }
        }
        else throw std::runtime_error("\""+args[1].str+"\": bad argument");
        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;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeLub(const TokenList &list) {
void Assembler::encodeLub(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("lub instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("lub 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=0x2A000000;
        LinkableObject::Word w=0x2A000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeLw(const TokenList &list) {
void Assembler::encodeLw(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("lw instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("lw 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=0x22000000;
        LinkableObject::Word w=0x22000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeMods(const TokenList &list) {
void Assembler::encodeMods(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("mods instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("mods instruction requires 3 operands");
        LinkableObject::Word w=0x5C000000;
        LinkableObject::Word w=0x5C000000;
        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::encodeModu(const TokenList &list) {
void Assembler::encodeModu(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("modu instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("modu instruction requires 3 operands");
        LinkableObject::Word w=0x58000000;
        LinkableObject::Word w=0x58000000;
        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::encodeMov(const TokenList &list) {
void Assembler::encodeMov(const TokenList &list) {
// Note: "mov" is not a real instruction, but an alias for "add dst, src, 0"
// Note: "mov" is not a real instruction, but an alias for "add dst, src, 0"
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("mov instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("mov instruction requires 2 operands");
        LinkableObject::Word w=0x40000000;
        LinkableObject::Word w=0x40000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeMul(const TokenList &list) {
void Assembler::encodeMul(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("mul instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("mul instruction requires 3 operands");
        LinkableObject::Word w=0x48000000;
        LinkableObject::Word w=0x48000000;
        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::encodeNeg(const TokenList &list) {
void Assembler::encodeNeg(const TokenList &list) {
// Note: "neg" is not a real instruction, but an alias for "sub dst, 0, src"
// Note: "neg" is not a real instruction, but an alias for "sub dst, 0, src"
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("neg instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("neg instruction requires 2 operands");
        LinkableObject::Word w=0x44000000;
        LinkableObject::Word w=0x44000000;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd2Operand(w,args[1]);
        encodeRd2Operand(w,args[1]);
        _obj.addWord(w);
        _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);
}
}
 
 
void Assembler::encodeNot(const TokenList &list) {
void Assembler::encodeNot(const TokenList &list) {
// Note: "not" is not a real instruction, but an alias for "xor dst, src, -1"
// Note: "not" is not a real instruction, but an alias for "xor dst, src, -1"
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("not instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("not instruction requires 2 operands");
        LinkableObject::Word w=0x680000FF;
        LinkableObject::Word w=0x680000FF;
        encodeDstOperand(w,args[0]);
        encodeDstOperand(w,args[0]);
        encodeRd1Operand(w,args[1]);
        encodeRd1Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeOr(const TokenList &list) {
void Assembler::encodeOr(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("or instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("or instruction requires 3 operands");
        LinkableObject::Word w=0x64000000;
        LinkableObject::Word w=0x64000000;
        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::encodeRet(const TokenList &list) {
void Assembler::encodeRet(const TokenList &list) {
// Note: "ret" is not a real instruction, but an alias for "jmp rp"
// Note: "ret" is not a real instruction, but an alias for "jmp rp"
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(!args.empty()) throw std::runtime_error("ret instruction doesn't take operands");
        if(!args.empty()) throw std::runtime_error("ret instruction doesn't take operands");
        _obj.addWord(0x8200FE00);
        _obj.addWord(0x8200FE00);
}
}
 
 
void Assembler::encodeSb(const TokenList &list) {
void Assembler::encodeSb(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("sb instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("sb instruction requires 2 operands");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        if(args[1].type==Operand::NumericLiteral) {
        if(args[1].type==Operand::NumericLiteral) {
// If numeric literal value is between 128 and 255 (inclusive), convert
// If numeric literal value is between 128 and 255 (inclusive), convert
// it to a signed byte to avoid exception in encodeRd2Operand()
// it to a signed byte to avoid exception in encodeRd2Operand()
                if(args[1].i>=128&&args[1].i<=255) args[1].i-=256;
                if(args[1].i>=128&&args[1].i<=255) args[1].i-=256;
        }
        }
        LinkableObject::Word w=0x3A000000;
        LinkableObject::Word w=0x3A000000;
        encodeRd1Operand(w,args[0]);
        encodeRd1Operand(w,args[0]);
        encodeRd2Operand(w,args[1]);
        encodeRd2Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeSl(const TokenList &list) {
void Assembler::encodeSl(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("sl instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("sl instruction requires 3 operands");
        if(args[2].type==Operand::NumericLiteral&&
        if(args[2].type==Operand::NumericLiteral&&
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
        {
        {
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
                        "the second operand is negative or greater than 31"<<std::endl;
                        "the second operand is negative or greater than 31"<<std::endl;
        }
        }
 
 
        LinkableObject::Word w=0x70000000;
        LinkableObject::Word w=0x70000000;
        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::encodeSrs(const TokenList &list) {
void Assembler::encodeSrs(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("srs instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("srs instruction requires 3 operands");
        if(args[2].type==Operand::NumericLiteral&&
        if(args[2].type==Operand::NumericLiteral&&
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
        {
        {
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
                        "the second operand is negative or greater than 31"<<std::endl;
                        "the second operand is negative or greater than 31"<<std::endl;
        }
        }
 
 
        LinkableObject::Word w=0x7C000000;
        LinkableObject::Word w=0x7C000000;
        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::encodeSru(const TokenList &list) {
void Assembler::encodeSru(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("sru instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("sru instruction requires 3 operands");
        if(args[2].type==Operand::NumericLiteral&&
        if(args[2].type==Operand::NumericLiteral&&
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
        {
        {
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
                        "the second operand is negative or greater than 31"<<std::endl;
                        "the second operand is negative or greater than 31"<<std::endl;
        }
        }
 
 
        LinkableObject::Word w=0x78000000;
        LinkableObject::Word w=0x78000000;
        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::encodeSub(const TokenList &list) {
void Assembler::encodeSub(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("sub instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("sub instruction requires 3 operands");
        LinkableObject::Word w=0x44000000;
        LinkableObject::Word w=0x44000000;
        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::encodeSw(const TokenList &list) {
void Assembler::encodeSw(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=2) throw std::runtime_error("sw instruction requires 2 operands");
        if(args.size()!=2) throw std::runtime_error("sw instruction requires 2 operands");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
        LinkableObject::Word w=0x32000000;
        LinkableObject::Word w=0x32000000;
        encodeRd1Operand(w,args[0]);
        encodeRd1Operand(w,args[0]);
        encodeRd2Operand(w,args[1]);
        encodeRd2Operand(w,args[1]);
        _obj.addWord(w);
        _obj.addWord(w);
}
}
 
 
void Assembler::encodeXor(const TokenList &list) {
void Assembler::encodeXor(const TokenList &list) {
        auto args=getOperands(list);
        auto args=getOperands(list);
        if(args.size()!=3) throw std::runtime_error("xor instruction requires 3 operands");
        if(args.size()!=3) throw std::runtime_error("xor instruction requires 3 operands");
        LinkableObject::Word w=0x68000000;
        LinkableObject::Word w=0x68000000;
        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);
}
}
 
 

powered by: WebSVN 2.1.0

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