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

Subversion Repositories lxp32

[/] [lxp32/] [trunk/] [tools/] [src/] [lxp32asm/] [assembler.cpp] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ring0_mipt
/*
2
 * Copyright (c) 2016 by Alex I. Kuznetsov.
3
 *
4
 * Part of the LXP32 CPU IP core.
5
 *
6
 * This module implements members of the Assembler class.
7
 */
8
 
9
#include "assembler.h"
10
#include "utils.h"
11
 
12
#include <iostream>
13
#include <fstream>
14
#include <sstream>
15
#include <stdexcept>
16
#include <utility>
17
#include <limits>
18
#include <type_traits>
19
#include <cctype>
20
#include <cassert>
21
#include <cstdlib>
22
 
23
void Assembler::processFile(const std::string &filename) {
24
        auto nativePath=Utils::normalizeSeparators(filename);
25
        auto pos=nativePath.find_last_of('/');
26
        if(pos!=std::string::npos) nativePath=filename.substr(pos+1);
27
        _obj.setName(nativePath);
28
 
29
        _line=0;
30
        _state=Initial;
31
        _currentFileName=filename;
32
        processFileRecursive(filename);
33
// Examine symbol table
34
        for(auto const &sym: _obj.symbols()) {
35
                if(sym.second.type==LinkableObject::Unknown&&!sym.second.refs.empty()) {
36
                        std::ostringstream msg;
37
                        msg<<"Undefined symbol \""+sym.first+"\"";
38
                        msg<<" (referenced from "<<sym.second.refs[0].source;
39
                        msg<<":"<<sym.second.refs[0].line<<")";
40
                        throw std::runtime_error(msg.str());
41
                }
42
        }
43
}
44
 
45
void Assembler::processFileRecursive(const std::string &filename) {
46
        std::ifstream in(filename,std::ios_base::in);
47
        if(!in) throw std::runtime_error("Cannot open file \""+filename+"\"");
48
 
49
// Process input file line-by-line
50
        auto savedLine=_line;
51
        auto savedState=_state;
52
        auto savedFileName=_currentFileName;
53
 
54
        _line=1;
55
        _state=Initial;
56
        _currentFileName=filename;
57
 
58
        std::string line;
59
        while(std::getline(in,line)) {
60
                auto tokens=tokenize(line);
61
                expand(tokens);
62
                elaborate(tokens);
63
                _line++;
64
        }
65
 
66
        _line=savedLine;
67
        _state=savedState;
68
        _currentFileName=savedFileName;
69
 
70
        for(auto const &label: _currentLabels) {
71
                _obj.addLocalSymbol(label,
72
                        static_cast<LinkableObject::Word>(_obj.codeSize()));
73
        }
74
 
75
        _currentLabels.clear();
76
}
77
 
78
void Assembler::addIncludeSearchDir(const std::string &dir) {
79
        auto ndir=Utils::normalizeSeparators(dir);
80
        if(!ndir.empty()&&ndir.back()!='/') ndir.push_back('/');
81
        _includeSearchDirs.push_back(std::move(ndir));
82
}
83
 
84
int Assembler::line() const {
85
        return _line;
86
}
87
 
88
std::string Assembler::currentFileName() const {
89
        return _currentFileName;
90
}
91
 
92
LinkableObject &Assembler::object() {
93
        return _obj;
94
}
95
 
96
const LinkableObject &Assembler::object() const {
97
        return _obj;
98
}
99
 
100
Assembler::TokenList Assembler::tokenize(const std::string &str) {
101
        TokenList tokenList;
102
        std::string word;
103
        std::size_t i;
104
        for(i=0;i<str.size();i++) {
105
                char ch=str[i];
106
                switch(_state) {
107
                case Initial:
108
                        if(ch==' '||ch=='\t'||ch=='\n'||ch=='\r') continue; // skip whitespace
109
                        else if(ch==','||ch==':') { // separator
110
                                tokenList.push_back(std::string(1,ch));
111
                        }
112
                        else if(std::isalnum(ch)||ch=='.'||ch=='#'||ch=='_'||ch=='-'||ch=='+') {
113
                                word=std::string(1,ch);
114
                                _state=Word;
115
                        }
116
                        else if(ch=='\"') {
117
                                word="\"";
118
                                _state=StringLiteral;
119
                        }
120
                        else if(ch=='/') {
121
                                if(++i>=str.size()) throw std::runtime_error("Unexpected end of line");
122
                                ch=str[i];
123
                                if(ch=='/') i=str.size(); // skip the rest of the line
124
                                else if(ch=='*') _state=BlockComment;
125
                                else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
126
                        }
127
                        else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
128
                        break;
129
                case Word:
130
                        if(std::isalnum(ch)||ch=='_'||ch=='@') word+=ch;
131
                        else {
132
                                i--;
133
                                _state=Initial;
134
                                tokenList.push_back(std::move(word));
135
                        }
136
                        break;
137
                case StringLiteral:
138
                        if(ch=='\\') {
139
                                if(++i>=str.size()) throw std::runtime_error("Unexpected end of line");
140
                                ch=str[i];
141
                                if(ch=='\\') word.push_back('\\');
142
                                else if(ch=='\"') word.push_back('\"');
143
                                else if(ch=='\'') word.push_back('\'');
144
                                else if(ch=='t') word.push_back('\t');
145
                                else if(ch=='n') word.push_back('\n');
146
                                else if(ch=='r') word.push_back('\r');
147
                                else if(ch=='x') { // hexadecimal sequence can be 1-2 digit long
148
                                        std::string seq;
149
                                        if(i+1<str.size()&&Utils::ishexdigit(str[i+1])) seq+=str[i+1];
150
                                        if(i+2<str.size()&&Utils::ishexdigit(str[i+2])) seq+=str[i+2];
151
                                        if(seq.empty()) throw std::runtime_error("Ill-formed escape sequence");
152
                                        try {
153
                                                word.push_back(static_cast<char>(std::stoul(seq,nullptr,16)));
154
                                        }
155
                                        catch(std::exception &) {
156
                                                throw std::runtime_error("Ill-formed escape sequence");
157
                                        }
158
                                        i+=seq.size();
159
                                }
160
                                else if(Utils::isoctdigit(ch)) { // octal sequence can be 1-3 digit long
161
                                        std::string seq(1,ch);
162
                                        if(i+1<str.size()&&Utils::isoctdigit(str[i+1])) seq+=str[i+1];
163
                                        if(i+2<str.size()&&Utils::isoctdigit(str[i+2])) seq+=str[i+2];
164
                                        unsigned long value;
165
                                        try {
166
                                                value=std::stoul(seq,nullptr,8);
167
                                        }
168
                                        catch(std::exception &) {
169
                                                throw std::runtime_error("Ill-formed escape sequence");
170
                                        }
171
 
172
                                        if(value>255) throw std::runtime_error("Octal value is out of range");
173
                                        word.push_back(static_cast<char>(value));
174
 
175
                                        i+=seq.size()-1;
176
                                }
177
                                else throw std::runtime_error(std::string("Unknown escape sequence: \"\\")+ch+"\"");
178
                        }
179
                        else if(ch=='\"') {
180
                                word.push_back('\"');
181
                                tokenList.push_back(std::move(word));
182
                                _state=Initial;
183
                        }
184
                        else word.push_back(ch);
185
                        break;
186
                case BlockComment:
187
                        if(ch=='*') {
188
                                if(++i>=str.size()) break;
189
                                ch=str[i];
190
                                if(ch=='/') _state=Initial;
191
                                else i--;
192
                        }
193
                        break;
194
                }
195
        }
196
 
197
        if(_state==StringLiteral) throw std::runtime_error("Unexpected end of line");
198
        if(_state==Word) tokenList.push_back(std::move(word)); // store last word
199
        if(_state!=BlockComment) _state=Initial; // reset state if not in block comment
200
 
201
        return tokenList;
202
}
203
 
204
void Assembler::expand(TokenList &list) {
205
        TokenList newlist;
206
// Perform macro substitution
207
        for(auto &token: list) {
208
                auto it=_macros.find(token);
209
                if(it==_macros.end()) newlist.push_back(std::move(token));
210
                else for(auto const &replace: it->second) newlist.push_back(replace);
211
        }
212
        list=std::move(newlist);
213
}
214
 
215
void Assembler::elaborate(TokenList &list) {
216
        if(list.empty()) return;
217
 
218
// Process label (if present)
219
        if(list.size()>=2&&list[1]==":") {
220
                if(!validateIdentifier(list[0]))
221
                        throw std::runtime_error("Ill-formed identifier: \""+list[0]+"\"");
222
                _currentLabels.push_back(std::move(list[0]));
223
                list.erase(list.begin(),list.begin()+2);
224
        }
225
 
226
        if(list.empty()) return;
227
 
228
// Process statement itself
229
        if(list[0][0]=='#') elaborateDirective(list);
230
        else {
231
                LinkableObject::Word rva;
232
                if(list[0][0]=='.') rva=elaborateDataDefinition(list);
233
                else rva=elaborateInstruction(list);
234
 
235
                for(auto const &label: _currentLabels) {
236
                        _obj.addLocalSymbol(label,rva);
237
                }
238
                _currentLabels.clear();
239
        }
240
}
241
 
242
void Assembler::elaborateDirective(TokenList &list) {
243
        assert(!list.empty());
244
 
245
        if(list[0]=="#define") {
246
                if(list.size()<3) throw std::runtime_error("Wrong number of tokens in the directive");
247
                if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
248
                _macros.emplace(list[1],TokenList(list.begin()+2,list.end()));
249
        }
250
        else if(list[0]=="#extern") {
251
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
252
                if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
253
                _obj.addExternalSymbol(list[1]);
254
        }
255
        else if(list[0]=="#include") {
256
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
257
                auto filename=Utils::dequoteString(list[1]);
258
                if(Utils::isAbsolutePath(filename)) return processFileRecursive(filename);
259
                else {
260
                        auto path=Utils::relativePath(currentFileName(),filename);
261
                        if(Utils::fileExists(path)) return processFileRecursive(path);
262
                        else {
263
                                for(auto const &dir: _includeSearchDirs) {
264
                                        path=Utils::nativeSeparators(dir+filename);
265
                                        if(Utils::fileExists(path)) return processFileRecursive(path);
266
                                }
267
                        }
268
                }
269
                throw std::runtime_error("Cannot locate include file \""+filename+"\"");
270
        }
271
        else if(list[0]=="#message") {
272
                if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
273
                auto msg=Utils::dequoteString(list[1]);
274
                std::cout<<currentFileName()<<":"<<line()<<": "<<msg<<std::endl;
275
        }
276
        else throw std::runtime_error("Unrecognized directive: \""+list[0]+"\"");
277
}
278
 
279
LinkableObject::Word Assembler::elaborateDataDefinition(TokenList &list) {
280
        assert(!list.empty());
281
 
282
        LinkableObject::Word rva=0;
283
 
284
        if(list[0]==".align") {
285
                if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
286
                std::size_t align=4;
287
                if(list.size()>1) align=static_cast<std::size_t>(numericLiteral(list[1]));
288
                rva=_obj.addPadding(align);
289
        }
290
        else if(list[0]==".reserve") {
291
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
292
                else if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
293
                auto n=static_cast<std::size_t>(numericLiteral(list[1]));
294
                rva=_obj.addZeros(n);
295
        }
296
        else if(list[0]==".word") {
297
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
298
                for(std::size_t i=1;i<list.size();i++) {
299
                        if(i%2!=0) {
300
                                auto w=static_cast<LinkableObject::Word>(numericLiteral(list[i]));
301
                                auto r=_obj.addWord(w);
302
                                if(i==1) rva=r;
303
                        }
304
                        else {
305
                                if(list[i]!=",") throw std::runtime_error("Comma expected");
306
                                if(i+1==list.size()) throw std::runtime_error("Unexpected end of statement");
307
                        }
308
                }
309
        }
310
        else if(list[0]==".byte") {
311
                if(list.size()<2) throw std::runtime_error("Unexpected end of statement");
312
                for(std::size_t i=1;i<list.size();i++) {
313
                        if(i%2!=0) {
314
                                if(list[i].at(0)=='\"') { // string literal
315
                                        auto bytes=Utils::dequoteString(list[i]);
316
                                        auto r=_obj.addBytes(reinterpret_cast<const LinkableObject::Byte*>
317
                                                (bytes.c_str()),bytes.size());
318
                                        if(i==1) rva=r;
319
                                }
320
                                else {
321
                                        auto n=numericLiteral(list[i]);
322
 
323
                                        if(n>255||n<-128) throw std::runtime_error("\""+list[i]+"\": out of range");
324
 
325
                                        auto b=static_cast<LinkableObject::Byte>(n);
326
                                        auto r=_obj.addByte(b);
327
                                        if(i==1) rva=r;
328
                                }
329
                        }
330
                        else {
331
                                if(list[i]!=",") throw std::runtime_error("Comma expected");
332
                                if(i+1==list.size()) throw std::runtime_error("Unexpected end of statement");
333
                        }
334
                }
335
        }
336
        else throw std::runtime_error("Unrecognized statement: \""+list[0]+"\"");
337
 
338
        return rva;
339
}
340
 
341
LinkableObject::Word Assembler::elaborateInstruction(TokenList &list) {
342
        assert(!list.empty());
343
        auto rva=_obj.addPadding();
344
        if(list[0]=="add") encodeAdd(list);
345
        else if(list[0]=="and") encodeAnd(list);
346
        else if(list[0]=="call") encodeCall(list);
347
        else if(list[0].substr(0,4)=="cjmp") encodeCjmpxx(list);
348
        else if(list[0]=="divs") encodeDivs(list);
349
        else if(list[0]=="divu") encodeDivu(list);
350
        else if(list[0]=="hlt") encodeHlt(list);
351
        else if(list[0]=="jmp") encodeJmp(list);
352
        else if(list[0]=="iret") encodeIret(list);
353
        else if(list[0]=="lc") encodeLc(list);
354
        else if(list[0]=="lsb") encodeLsb(list);
355
        else if(list[0]=="lub") encodeLub(list);
356
        else if(list[0]=="lw") encodeLw(list);
357
        else if(list[0]=="mods") encodeMods(list);
358
        else if(list[0]=="modu") encodeModu(list);
359
        else if(list[0]=="mov") encodeMov(list);
360
        else if(list[0]=="mul") encodeMul(list);
361
        else if(list[0]=="nop") encodeNop(list);
362
        else if(list[0]=="not") encodeNot(list);
363
        else if(list[0]=="or") encodeOr(list);
364
        else if(list[0]=="ret") encodeRet(list);
365
        else if(list[0]=="sb") encodeSb(list);
366
        else if(list[0]=="sl") encodeSl(list);
367
        else if(list[0]=="srs") encodeSrs(list);
368
        else if(list[0]=="sru") encodeSru(list);
369
        else if(list[0]=="sub") encodeSub(list);
370
        else if(list[0]=="sw") encodeSw(list);
371
        else if(list[0]=="xor") encodeXor(list);
372
        else throw std::runtime_error("Unrecognized instruction: \""+list[0]+"\"");
373
        return rva;
374
}
375
 
376
bool Assembler::validateIdentifier(const std::string &str) {
377
/*
378
 * Valid identifier must satisfy the following requirements:
379
 *  1. Must not be empty
380
 *  2. The first character must be either alphabetic or an underscore
381
 *  3. Subsequent characters must be either alphanumeric or underscores
382
 */
383
        if(str.empty()) return false;
384
        for(std::size_t i=0;i<str.size();i++) {
385
                char ch=str[i];
386
                if(i==0) {
387
                        if(!std::isalpha(ch)&&ch!='_') return false;
388
                }
389
                else {
390
                        if(!std::isalnum(ch)&&ch!='_') return false;
391
                }
392
        }
393
        return true;
394
}
395
 
396
Assembler::Integer Assembler::numericLiteral(const std::string &str) {
397
        std::size_t pos;
398
        Integer i;
399
        try {
400
                i=std::stoll(str,&pos,0);
401
        }
402
        catch(std::exception &) {
403
                throw std::runtime_error("Ill-formed numeric literal: \""+str+"\"");
404
        }
405
        if(pos<str.size()) throw std::runtime_error("Ill-formed numeric literal: \""+str+"\"");
406
 
407
        typedef std::make_signed<LinkableObject::Word>::type SignedWord;
408
 
409
        if(i>static_cast<Integer>(std::numeric_limits<LinkableObject::Word>::max())||
410
                i<static_cast<Integer>(std::numeric_limits<SignedWord>::min()))
411
                        throw std::runtime_error("\""+str+"\": out of range");
412
 
413
        return i;
414
}
415
 
416
std::vector<Assembler::Operand> Assembler::getOperands(const TokenList &list) {
417
        std::vector<Operand> arglist;
418
        for(std::size_t i=1;i<list.size();i++) {
419
                if(i%2!=0) {
420
                        Operand a;
421
                        a.str=list[i];
422
 
423
                        if(!list[i].empty()&&list[i][0]=='r') {
424
// Is argument a register?
425
                                char *endptr;
426
                                auto regstr=list[i].substr(1);
427
                                auto reg=std::strtol(regstr.c_str(),&endptr,10);
428
 
429
                                if(!*endptr&&reg>=0&&reg<=255) {
430
                                        a.type=Operand::Register;
431
                                        a.reg=static_cast<std::uint8_t>(reg);
432
                                        arglist.push_back(std::move(a));
433
                                        continue;
434
                                }
435
                        }
436
 
437
// Try alternative register names
438
                        if(list[i]=="sp") { // stack pointer
439
                                a.type=Operand::Register;
440
                                a.reg=255;
441
                                arglist.push_back(std::move(a));
442
                        }
443
                        else if(list[i]=="rp") { // return pointer
444
                                a.type=Operand::Register;
445
                                a.reg=254;
446
                                arglist.push_back(std::move(a));
447
                        }
448
                        else if(list[i]=="irp") { // interrupt return pointer
449
                                a.type=Operand::Register;
450
                                a.reg=253;
451
                                arglist.push_back(std::move(a));
452
                        }
453
                        else if(list[i]=="cr") { // control register
454
                                a.type=Operand::Register;
455
                                a.reg=252;
456
                                arglist.push_back(std::move(a));
457
                        }
458
                        else if(list[i].size()==3&&list[i].substr(0,2)=="iv"&&
459
                                std::isdigit(list[i][2])) // interrupt vector
460
                        {
461
                                a.type=Operand::Register;
462
                                a.reg=240+(list[i][2]-'0');
463
                                arglist.push_back(std::move(a));
464
                        }
465
                        else if(validateIdentifier(list[i])) {
466
// Is argument an identifier?
467
                                a.type=Operand::Identifier;
468
                                arglist.push_back(std::move(a));
469
                        }
470
                        else {
471
                                auto atpos=list[i].find_first_of('@');
472
                                if(atpos!=std::string::npos) {
473
// Identifier with an offset?
474
                                        a.type=Operand::Identifier;
475
                                        a.str=list[i].substr(0,atpos);
476
                                        if(!validateIdentifier(a.str)) throw std::runtime_error("Ill-formed identifier");
477
                                        a.i=numericLiteral(list[i].substr(atpos+1));
478
                                        arglist.push_back(std::move(a));
479
                                }
480
                                else {
481
// Numeric literal?
482
                                        a.type=Operand::NumericLiteral;
483
                                        a.i=numericLiteral(list[i]);
484
                                        arglist.push_back(std::move(a));
485
                                }
486
                        }
487
                }
488
                else {
489
                        if(list[i]!=",") throw std::runtime_error("Comma expected");
490
                        if(i+1==list.size()) throw std::runtime_error("Unexpected end of line");
491
                }
492
        }
493
        return arglist;
494
}
495
 
496
/*
497
 * Member functions to encode LXP32 instructions
498
 */
499
 
500
void Assembler::encodeDstOperand(LinkableObject::Word &word,const Operand &arg) {
501
        if(arg.type!=Operand::Register)
502
                throw std::runtime_error("\""+arg.str+"\": must be a register");
503
        word|=arg.reg<<16;
504
}
505
 
506
void Assembler::encodeRd1Operand(LinkableObject::Word &word,const Operand &arg) {
507
        if(arg.type==Operand::Register) {
508
                word|=0x02000000;
509
                word|=arg.reg<<8;
510
        }
511
        else if(arg.type==Operand::NumericLiteral) {
512
                if((arg.i<-128||arg.i>127)&&(arg.i<0xFFFFFF80||arg.i>0xFFFFFFFF))
513
                        throw std::runtime_error("\""+arg.str+"\": out of range");
514
                auto b=static_cast<LinkableObject::Byte>(arg.i);
515
                word|=b<<8;
516
        }
517
        else throw std::runtime_error("\""+arg.str+"\": bad argument");
518
}
519
 
520
void Assembler::encodeRd2Operand(LinkableObject::Word &word,const Operand &arg) {
521
        if(arg.type==Operand::Register) {
522
                word|=0x01000000;
523
                word|=arg.reg;
524
        }
525
        else if(arg.type==Operand::NumericLiteral) {
526
                if((arg.i<-128||arg.i>127)&&(arg.i<0xFFFFFF80||arg.i>0xFFFFFFFF))
527
                        throw std::runtime_error("\""+arg.str+"\": out of range");
528
                auto b=static_cast<LinkableObject::Byte>(arg.i);
529
                word|=b;
530
        }
531
        else throw std::runtime_error("\""+arg.str+"\": bad argument");
532
}
533
 
534
void Assembler::encodeAdd(const TokenList &list) {
535
        auto args=getOperands(list);
536
        if(args.size()!=3) throw std::runtime_error("add instruction requires 3 operands");
537
        LinkableObject::Word w=0x40000000;
538
        encodeDstOperand(w,args[0]);
539
        encodeRd1Operand(w,args[1]);
540
        encodeRd2Operand(w,args[2]);
541
        _obj.addWord(w);
542
}
543
 
544
void Assembler::encodeAnd(const TokenList &list) {
545
        auto args=getOperands(list);
546
        if(args.size()!=3) throw std::runtime_error("and instruction requires 3 operands");
547
        LinkableObject::Word w=0x60000000;
548
        encodeDstOperand(w,args[0]);
549
        encodeRd1Operand(w,args[1]);
550
        encodeRd2Operand(w,args[2]);
551
        _obj.addWord(w);
552
}
553
 
554
void Assembler::encodeCall(const TokenList &list) {
555
        auto args=getOperands(list);
556
        if(args.size()!=1) throw std::runtime_error("call instruction requires 1 operand");
557
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
558
        LinkableObject::Word w=0x86FE0000;
559
        encodeRd1Operand(w,args[0]);
560
        _obj.addWord(w);
561
}
562
 
563
void Assembler::encodeCjmpxx(const TokenList &list) {
564
        auto args=getOperands(list);
565
        if(args.size()!=3) throw std::runtime_error("cjmpxx instruction requires 3 operands");
566
 
567
        LinkableObject::Word w;
568
        bool reverse=false;
569
/*
570
 * Note: cjmpul, cjmpule, cjmpsl and cjmpsle don't have distinct opcodes;
571
 * instead, they are aliases for respective "g" or "ge" instructions
572
 * with reversed operand order.
573
 */
574
        if(list[0]=="cjmpe") w=0xE0000000;
575
        else if(list[0]=="cjmpne") w=0xD0000000;
576
        else if(list[0]=="cjmpug"||list[0]=="cjmpul") w=0xC8000000;
577
        else if(list[0]=="cjmpuge"||list[0]=="cjmpule") w=0xE8000000;
578
        else if(list[0]=="cjmpsg"||list[0]=="cjmpsl") w=0xC4000000;
579
        else if(list[0]=="cjmpsge"||list[0]=="cjmpsle") w=0xE4000000;
580
        else throw std::runtime_error("Unrecognized instruction: \""+list[0]+"\"");
581
 
582
        if(list[0]=="cjmpul"||list[0]=="cjmpule"||
583
                list[0]=="cjmpsl"||list[0]=="cjmpsle") reverse=true;
584
 
585
        encodeDstOperand(w,args[0]);
586
 
587
        if(!reverse) {
588
                encodeRd1Operand(w,args[1]);
589
                encodeRd2Operand(w,args[2]);
590
        }
591
        else {
592
                encodeRd1Operand(w,args[2]);
593
                encodeRd2Operand(w,args[1]);
594
        }
595
        _obj.addWord(w);
596
}
597
 
598
void Assembler::encodeDivs(const TokenList &list) {
599
        auto args=getOperands(list);
600
        if(args.size()!=3) throw std::runtime_error("divs instruction requires 3 operands");
601
        if(args[2].type==Operand::NumericLiteral&&args[2].i==0) {
602
                std::cerr<<currentFileName()<<":"<<line()<<": ";
603
                std::cerr<<"Warning: Division by zero"<<std::endl;
604
        }
605
 
606
        LinkableObject::Word w=0x54000000;
607
        encodeDstOperand(w,args[0]);
608
        encodeRd1Operand(w,args[1]);
609
        encodeRd2Operand(w,args[2]);
610
        _obj.addWord(w);
611
}
612
 
613
void Assembler::encodeDivu(const TokenList &list) {
614
        auto args=getOperands(list);
615
        if(args.size()!=3) throw std::runtime_error("divu instruction requires 3 operands");
616
        if(args[2].type==Operand::NumericLiteral&&args[2].i==0) {
617
                std::cerr<<currentFileName()<<":"<<line()<<": ";
618
                std::cerr<<"Warning: Division by zero"<<std::endl;
619
        }
620
 
621
        LinkableObject::Word w=0x50000000;
622
        encodeDstOperand(w,args[0]);
623
        encodeRd1Operand(w,args[1]);
624
        encodeRd2Operand(w,args[2]);
625
        _obj.addWord(w);
626
}
627
 
628
void Assembler::encodeHlt(const TokenList &list) {
629
        auto args=getOperands(list);
630
        if(!args.empty()) throw std::runtime_error("hlt instruction doesn't take operands");
631
        _obj.addWord(0x08000000);
632
}
633
 
634
void Assembler::encodeJmp(const TokenList &list) {
635
        auto args=getOperands(list);
636
        if(args.size()!=1) throw std::runtime_error("jmp instruction requires 1 operand");
637
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
638
        LinkableObject::Word w=0x82000000;
639
        encodeRd1Operand(w,args[0]);
640
        _obj.addWord(w);
641
}
642
 
643
void Assembler::encodeIret(const TokenList &list) {
644
// Note: "iret" is not a real instruction, but an alias for "jmp irp"
645
        auto args=getOperands(list);
646
        if(!args.empty()) throw std::runtime_error("iret instruction doesn't take operands");
647
        _obj.addWord(0x8200FD00);
648
}
649
 
650
void Assembler::encodeLc(const TokenList &list) {
651
        auto args=getOperands(list);
652
        if(args.size()!=2) throw std::runtime_error("lc instruction requires 2 operands");
653
 
654
        LinkableObject::Word w=0x04000000;
655
        encodeDstOperand(w,args[0]);
656
        _obj.addWord(w);
657
 
658
        if(args[1].type==Operand::Identifier) {
659
                auto symRva=_obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
660
                _obj.addReference(args[1].str,currentFileName(),line(),symRva);
661
        }
662
        else if(args[1].type==Operand::NumericLiteral) {
663
                _obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
664
        }
665
        else throw std::runtime_error("\""+args[1].str+"\": bad argument");
666
}
667
 
668
void Assembler::encodeLsb(const TokenList &list) {
669
        auto args=getOperands(list);
670
        if(args.size()!=2) throw std::runtime_error("lsb instruction requires 2 operands");
671
        if(args[1].type!=Operand::Register) throw std::runtime_error("\""+args[1].str+"\": must be a register");
672
        LinkableObject::Word w=0x2E000000;
673
        encodeDstOperand(w,args[0]);
674
        encodeRd1Operand(w,args[1]);
675
        _obj.addWord(w);
676
}
677
 
678
void Assembler::encodeLub(const TokenList &list) {
679
        auto args=getOperands(list);
680
        if(args.size()!=2) throw std::runtime_error("lub instruction requires 2 operands");
681
        if(args[1].type!=Operand::Register) throw std::runtime_error("\""+args[1].str+"\": must be a register");
682
        LinkableObject::Word w=0x2A000000;
683
        encodeDstOperand(w,args[0]);
684
        encodeRd1Operand(w,args[1]);
685
        _obj.addWord(w);
686
}
687
 
688
void Assembler::encodeLw(const TokenList &list) {
689
        auto args=getOperands(list);
690
        if(args.size()!=2) throw std::runtime_error("lw instruction requires 2 operands");
691
        if(args[1].type!=Operand::Register) throw std::runtime_error("\""+args[1].str+"\": must be a register");
692
        LinkableObject::Word w=0x22000000;
693
        encodeDstOperand(w,args[0]);
694
        encodeRd1Operand(w,args[1]);
695
        _obj.addWord(w);
696
}
697
 
698
void Assembler::encodeMods(const TokenList &list) {
699
        auto args=getOperands(list);
700
        if(args.size()!=3) throw std::runtime_error("mods instruction requires 3 operands");
701
        LinkableObject::Word w=0x5C000000;
702
        encodeDstOperand(w,args[0]);
703
        encodeRd1Operand(w,args[1]);
704
        encodeRd2Operand(w,args[2]);
705
        _obj.addWord(w);
706
}
707
 
708
void Assembler::encodeModu(const TokenList &list) {
709
        auto args=getOperands(list);
710
        if(args.size()!=3) throw std::runtime_error("modu instruction requires 3 operands");
711
        LinkableObject::Word w=0x58000000;
712
        encodeDstOperand(w,args[0]);
713
        encodeRd1Operand(w,args[1]);
714
        encodeRd2Operand(w,args[2]);
715
        _obj.addWord(w);
716
}
717
 
718
void Assembler::encodeMov(const TokenList &list) {
719
// Note: "mov" is not a real instruction, but an alias for "add dst, src, 0"
720
        auto args=getOperands(list);
721
        if(args.size()!=2) throw std::runtime_error("mov instruction requires 2 operands");
722
        LinkableObject::Word w=0x40000000;
723
        encodeDstOperand(w,args[0]);
724
        encodeRd1Operand(w,args[1]);
725
        _obj.addWord(w);
726
}
727
 
728
void Assembler::encodeMul(const TokenList &list) {
729
        auto args=getOperands(list);
730
        if(args.size()!=3) throw std::runtime_error("mul instruction requires 3 operands");
731
        LinkableObject::Word w=0x48000000;
732
        encodeDstOperand(w,args[0]);
733
        encodeRd1Operand(w,args[1]);
734
        encodeRd2Operand(w,args[2]);
735
        _obj.addWord(w);
736
}
737
 
738
void Assembler::encodeNop(const TokenList &list) {
739
        auto args=getOperands(list);
740
        if(!args.empty()) throw std::runtime_error("nop instruction doesn't take operands");
741
        _obj.addWord(0);
742
}
743
 
744
void Assembler::encodeNot(const TokenList &list) {
745
// Note: "not" is not a real instruction, but an alias for "xor dst, src, -1"
746
        auto args=getOperands(list);
747
        if(args.size()!=2) throw std::runtime_error("not instruction requires 2 operands");
748
        LinkableObject::Word w=0x680000FF;
749
        encodeDstOperand(w,args[0]);
750
        encodeRd1Operand(w,args[1]);
751
        _obj.addWord(w);
752
}
753
 
754
void Assembler::encodeOr(const TokenList &list) {
755
        auto args=getOperands(list);
756
        if(args.size()!=3) throw std::runtime_error("or instruction requires 3 operands");
757
        LinkableObject::Word w=0x64000000;
758
        encodeDstOperand(w,args[0]);
759
        encodeRd1Operand(w,args[1]);
760
        encodeRd2Operand(w,args[2]);
761
        _obj.addWord(w);
762
}
763
 
764
void Assembler::encodeRet(const TokenList &list) {
765
// Note: "ret" is not a real instruction, but an alias for "jmp rp"
766
        auto args=getOperands(list);
767
        if(!args.empty()) throw std::runtime_error("ret instruction doesn't take operands");
768
        _obj.addWord(0x8200FE00);
769
}
770
 
771
void Assembler::encodeSb(const TokenList &list) {
772
        auto args=getOperands(list);
773
        if(args.size()!=2) throw std::runtime_error("sb instruction requires 2 operands");
774
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
775
        if(args[1].type==Operand::NumericLiteral) {
776
// If numeric literal value is between 128 and 255 (inclusive), convert
777
// it to a signed byte to avoid exception in encodeRd2Operand()
778
                if(args[1].i>=128&&args[1].i<=255) args[1].i-=256;
779
        }
780
        LinkableObject::Word w=0x3A000000;
781
        encodeRd1Operand(w,args[0]);
782
        encodeRd2Operand(w,args[1]);
783
        _obj.addWord(w);
784
}
785
 
786
void Assembler::encodeSl(const TokenList &list) {
787
        auto args=getOperands(list);
788
        if(args.size()!=3) throw std::runtime_error("sl instruction requires 3 operands");
789
        if(args[2].type==Operand::NumericLiteral&&
790
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
791
        {
792
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
793
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
794
                        "the second operand is negative or greater than 31"<<std::endl;
795
        }
796
 
797
        LinkableObject::Word w=0x70000000;
798
        encodeDstOperand(w,args[0]);
799
        encodeRd1Operand(w,args[1]);
800
        encodeRd2Operand(w,args[2]);
801
        _obj.addWord(w);
802
}
803
 
804
void Assembler::encodeSrs(const TokenList &list) {
805
        auto args=getOperands(list);
806
        if(args.size()!=3) throw std::runtime_error("srs instruction requires 3 operands");
807
        if(args[2].type==Operand::NumericLiteral&&
808
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
809
        {
810
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
811
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
812
                        "the second operand is negative or greater than 31"<<std::endl;
813
        }
814
 
815
        LinkableObject::Word w=0x7C000000;
816
        encodeDstOperand(w,args[0]);
817
        encodeRd1Operand(w,args[1]);
818
        encodeRd2Operand(w,args[2]);
819
        _obj.addWord(w);
820
}
821
 
822
void Assembler::encodeSru(const TokenList &list) {
823
        auto args=getOperands(list);
824
        if(args.size()!=3) throw std::runtime_error("sru instruction requires 3 operands");
825
        if(args[2].type==Operand::NumericLiteral&&
826
                (args[2].i<0||args[2].i>=static_cast<Integer>(8*sizeof(LinkableObject::Word))))
827
        {
828
                        std::cerr<<currentFileName()<<":"<<line()<<": ";
829
                        std::cerr<<"Warning: Bitwise shift result is undefined when "
830
                        "the second operand is negative or greater than 31"<<std::endl;
831
        }
832
 
833
        LinkableObject::Word w=0x78000000;
834
        encodeDstOperand(w,args[0]);
835
        encodeRd1Operand(w,args[1]);
836
        encodeRd2Operand(w,args[2]);
837
        _obj.addWord(w);
838
}
839
 
840
void Assembler::encodeSub(const TokenList &list) {
841
        auto args=getOperands(list);
842
        if(args.size()!=3) throw std::runtime_error("sub instruction requires 3 operands");
843
        LinkableObject::Word w=0x44000000;
844
        encodeDstOperand(w,args[0]);
845
        encodeRd1Operand(w,args[1]);
846
        encodeRd2Operand(w,args[2]);
847
        _obj.addWord(w);
848
}
849
 
850
void Assembler::encodeSw(const TokenList &list) {
851
        auto args=getOperands(list);
852
        if(args.size()!=2) throw std::runtime_error("sw instruction requires 2 operands");
853
        if(args[0].type!=Operand::Register) throw std::runtime_error("\""+args[0].str+"\": must be a register");
854
        LinkableObject::Word w=0x32000000;
855
        encodeRd1Operand(w,args[0]);
856
        encodeRd2Operand(w,args[1]);
857
        _obj.addWord(w);
858
}
859
 
860
void Assembler::encodeXor(const TokenList &list) {
861
        auto args=getOperands(list);
862
        if(args.size()!=3) throw std::runtime_error("xor instruction requires 3 operands");
863
        LinkableObject::Word w=0x68000000;
864
        encodeDstOperand(w,args[0]);
865
        encodeRd1Operand(w,args[1]);
866
        encodeRd2Operand(w,args[2]);
867
        _obj.addWord(w);
868
}

powered by: WebSVN 2.1.0

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