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

Subversion Repositories lxp32

[/] [lxp32/] [trunk/] [tools/] [src/] [lxp32asm/] [main.cpp] - Blame information for rev 9

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 ring0_mipt
/*
2
 * Copyright (c) 2016 by Alex I. Kuznetsov.
3
 *
4
 * Part of the LXP32 CPU IP core.
5
 *
6
 * Main translation unit for the LXP32 assembler/linker.
7
 */
8
 
9
#include "assembler.h"
10
#include "linker.h"
11
#include "utils.h"
12
 
13
#include <iostream>
14
#include <fstream>
15
#include <vector>
16
#include <string>
17
#include <exception>
18
#include <utility>
19
#include <memory>
20
#include <cstdlib>
21
#include <cstring>
22
#include <cassert>
23
 
24
struct Options {
25
        enum OutputFormat {Bin,Textio,Dec,Hex};
26
 
27
        bool compileOnly=false;
28
        std::string outputFileName;
29
        std::string mapFileName;
30
        std::vector<std::string> includeSearchDirs;
31
        LinkableObject::Word base=0;
32
        std::size_t align=4;
33
        std::size_t imageSize=0;
34
        OutputFormat fmt=Bin;
35
};
36
 
37
static void displayUsage(std::ostream &os,const char *program) {
38
        os<<std::endl;
39
        os<<"Usage:"<<std::endl;
40
        os<<"    "<<program<<" [ option(s) | input file(s) ]"<<std::endl<<std::endl;
41
 
42
        os<<"Options:"<<std::endl;
43
        os<<"    -a <align>   Object alignment (default: 4)"<<std::endl;
44
        os<<"    -b <addr>    Base address (default: 0)"<<std::endl;
45
        os<<"    -c           Compile only (don't link)"<<std::endl;
46
        os<<"    -f <fmt>     Output file format (see below)"<<std::endl;
47
        os<<"    -h, --help   Display a short help message"<<std::endl;
48
        os<<"    -i <dir>     Add directory to the list of directories used to search"<<std::endl;
49
        os<<"                 for included files (multiple directories can be specified)"<<std::endl;
50
        os<<"    -m <file>    Generate map file"<<std::endl;
51
        os<<"    -o <file>    Output file name"<<std::endl;
52
        os<<"    -s <size>    Output image size"<<std::endl;
53
        os<<"    --           Do not interpret subsequent arguments as options"<<std::endl;
54
        os<<std::endl;
55
        os<<"Object alignment must be a power of two and can't be less than 4."<<std::endl;
56
        os<<"Base address must be a multiple of object alignment."<<std::endl;
57
        os<<"Image size must be a multiple of 4."<<std::endl;
58
        os<<std::endl;
59
 
60
        os<<"Output file formats:"<<std::endl;
61
        os<<"    bin          Raw binary image (default)"<<std::endl;
62
        os<<"    textio       Text representation of binary data. Supported by"<<std::endl;
63
        os<<"                 std.textio (VHDL) and $readmemb (Verilog)"<<std::endl;
64
        os<<"    dec          Text format, one word per line (decimal)"<<std::endl;
65
        os<<"    hex          Text format, one word per line (hexadecimal)"<<std::endl;
66
}
67
 
68
static bool isLinkableObject(const std::string &filename) {
69
        static const char *id="LinkableObject";
70
        static std::size_t idSize=std::strlen(id);
71
 
72
        std::ifstream in(filename,std::ios_base::in);
73
        if(!in) return false;
74
        if(in.tellg()==static_cast<std::ifstream::pos_type>(-1))
75
                return false; // the stream is not seekable
76
 
77
        std::vector<char> buf(idSize);
78
        in.read(buf.data(),idSize);
79
        if(static_cast<std::size_t>(in.gcount())!=idSize) return false;
80
        if(std::memcmp(buf.data(),id,idSize)) return false;
81
        return true;
82
}
83
 
84
int main(int argc,char *argv[]) try {
85
        std::vector<std::string> inputFiles;
86
        Options options;
87
        bool alignmentSpecified=false;
88
        bool baseSpecified=false;
89
        bool formatSpecified=false;
90
        bool noMoreOptions=false;
91
 
92
        std::cout<<"LXP32 Platform Assembler and Linker"<<std::endl;
93
        std::cout<<"Copyright (c) 2016-2019 by Alex I. Kuznetsov"<<std::endl;
94
 
95
        if(argc<=1) {
96
                displayUsage(std::cout,argv[0]);
97
                return 0;
98
        }
99
 
100
        for(int i=1;i<argc;i++) {
101
                if(argv[i][0]!='-'||noMoreOptions) inputFiles.push_back(argv[i]);
102
                else if(!strcmp(argv[i],"--")) noMoreOptions=true;
103
                else if(!strcmp(argv[i],"-a")) {
104
                        if(++i==argc) {
105
                                displayUsage(std::cerr,argv[0]);
106
                                return EXIT_FAILURE;
107
                        }
108
                        try {
109
                                options.align=std::stoul(argv[i],nullptr,0);
110
                                if(!Utils::isPowerOf2(options.align)) throw std::exception();
111
                                if(options.align<4) throw std::exception();
112
                                alignmentSpecified=true;
113
                        }
114
                        catch(std::exception &) {
115
                                throw std::runtime_error("Invalid object alignment");
116
                        }
117
                }
118
                else if(!strcmp(argv[i],"-b")) {
119
                        if(++i==argc) {
120
                                displayUsage(std::cerr,argv[0]);
121
                                return EXIT_FAILURE;
122
                        }
123
                        try {
124
                                options.base=std::stoul(argv[i],nullptr,0);
125
                                baseSpecified=true;
126
                        }
127
                        catch(std::exception &) {
128
                                throw std::runtime_error("Invalid base address");
129
                        }
130
                }
131
                else if(!strcmp(argv[i],"-c")) {
132
                        options.compileOnly=true;
133
                }
134
                else if(!strcmp(argv[i],"-f")) {
135
                        if(++i==argc) {
136
                                displayUsage(std::cerr,argv[0]);
137
                                return EXIT_FAILURE;
138
                        }
139
                        if(!strcmp(argv[i],"bin")) options.fmt=Options::Bin;
140
                        else if(!strcmp(argv[i],"textio")) options.fmt=Options::Textio;
141
                        else if(!strcmp(argv[i],"dec")) options.fmt=Options::Dec;
142
                        else if(!strcmp(argv[i],"hex")) options.fmt=Options::Hex;
143
                        else throw std::runtime_error("Unrecognized output format");
144
                        formatSpecified=true;
145
                }
146
                else if(!strcmp(argv[i],"-h")||!strcmp(argv[i],"--help")) {
147
                        displayUsage(std::cout,argv[0]);
148
                        return 0;
149
                }
150
                else if(!strcmp(argv[i],"-i")) {
151
                        if(++i==argc) {
152
                                displayUsage(std::cerr,argv[0]);
153
                                return EXIT_FAILURE;
154
                        }
155
                        options.includeSearchDirs.push_back(argv[i]);
156
                }
157
                else if(!strcmp(argv[i],"-m")) {
158
                        if(++i==argc) {
159
                                displayUsage(std::cerr,argv[0]);
160
                                return EXIT_FAILURE;
161
                        }
162
                        options.mapFileName=argv[i];
163
                }
164
                else if(!strcmp(argv[i],"-o")) {
165
                        if(++i==argc) {
166
                                displayUsage(std::cerr,argv[0]);
167
                                return EXIT_FAILURE;
168
                        }
169
                        options.outputFileName=argv[i];
170
                }
171
                else if(!strcmp(argv[i],"-s")) {
172
                        if(++i==argc) {
173
                                displayUsage(std::cerr,argv[0]);
174
                                return EXIT_FAILURE;
175
                        }
176
                        try {
177
                                options.imageSize=std::stoul(argv[i],nullptr,0);
178
                                if(options.imageSize%4!=0||options.imageSize==0) throw std::exception();
179
                        }
180
                        catch(std::exception &) {
181
                                throw std::runtime_error("Invalid image size");
182
                        }
183
                }
184
                else throw std::runtime_error(std::string("Unrecognized option: \"")+argv[i]+"\"");
185
        }
186
 
187
        if(options.base%options.align!=0)
188
                throw std::runtime_error("Base address must be a multiple of object alignment");
189
 
190
        if(options.compileOnly) {
191
                if(alignmentSpecified)
192
                        std::cerr<<"Warning: Object alignment is ignored in compile-only mode"<<std::endl;
193
                if(baseSpecified)
194
                        std::cerr<<"Warning: Base address is ignored in compile-only mode"<<std::endl;
195
                if(formatSpecified)
196
                        std::cerr<<"Warning: Output format is ignored in compile-only mode"<<std::endl;
197
                if(options.imageSize>0)
198
                        std::cerr<<"Warning: Image size is ignored in compile-only mode"<<std::endl;
199
                if(!options.mapFileName.empty())
200
                        std::cerr<<"Warning: Map file is not generated in compile-only mode"<<std::endl;
201
        }
202
 
203
        if(inputFiles.empty())
204
                throw std::runtime_error("No input files were specified");
205
 
206
        if(options.compileOnly&&inputFiles.size()>1&&!options.outputFileName.empty())
207
                throw std::runtime_error("Output file name cannot be specified "
208
                        "for multiple files in compile-only mode");
209
 
210
        std::vector<Assembler> assemblers;
211
        std::vector<LinkableObject> rawObjects;
212
 
213
        for(auto const &filename: inputFiles) {
214
                if(options.compileOnly||!isLinkableObject(filename)) {
215
                        Assembler as;
216
                        for(auto const &dir: options.includeSearchDirs) as.addIncludeSearchDir(dir);
217
                        try {
218
                                as.processFile(filename);
219
                        }
220
                        catch(std::exception &ex) {
221
                                std::cerr<<"Assembler error in "<<as.currentFileName();
222
                                if(as.line()>0) std::cerr<<":"<<as.line();
223
                                std::cerr<<": "<<ex.what()<<std::endl;
224
                                return EXIT_FAILURE;
225
                        }
226
                        if(!options.compileOnly) assemblers.push_back(std::move(as));
227
                        else {
228
                                std::string outputFileName=options.outputFileName;
229
                                if(outputFileName.empty()) {
230
                                        outputFileName=filename;
231
                                        auto pos=outputFileName.find_last_of('.');
232
                                        if(pos!=std::string::npos) outputFileName.erase(pos);
233
                                        outputFileName+=".lo";
234
                                }
235
                                as.object().serialize(outputFileName);
236
                        }
237
                }
238
                else {
239
                        LinkableObject lo;
240
                        try {
241
                                lo.deserialize(filename);
242
                        }
243
                        catch(std::exception &ex) {
244
                                std::cerr<<"Error reading object file "<<filename<<": "<<ex.what()<<std::endl;
245
                                return EXIT_FAILURE;
246
                        }
247
                        rawObjects.push_back(std::move(lo));
248
                }
249
        }
250
 
251
        if(options.compileOnly) return 0;
252
 
253
        Linker linker;
254
        for(auto &lo: rawObjects) linker.addObject(lo);
255
        for(auto &as: assemblers) linker.addObject(as.object());
256
        linker.setBase(options.base);
257
        linker.setAlignment(options.align);
258
        linker.setImageSize(options.imageSize);
259
 
260
        std::string outputFileName=options.outputFileName;
261
        if(outputFileName.empty()) {
262
                outputFileName=inputFiles[0];
263
                auto pos=outputFileName.find_last_of('.');
264
                if(pos!=std::string::npos) outputFileName.erase(pos);
265
                if(options.fmt==Options::Bin) outputFileName+=".bin";
266
                else outputFileName+=".txt";
267
        }
268
 
269
        std::unique_ptr<OutputWriter> writer;
270
 
271
        switch(options.fmt) {
272
        case Options::Bin:
273
                writer=std::unique_ptr<OutputWriter>(new BinaryOutputWriter(outputFileName));
274
                break;
275
        case Options::Textio:
276
                writer=std::unique_ptr<OutputWriter>(new TextOutputWriter(outputFileName,TextOutputWriter::Bin));
277
                break;
278
        case Options::Dec:
279
                writer=std::unique_ptr<OutputWriter>(new TextOutputWriter(outputFileName,TextOutputWriter::Dec));
280
                break;
281
        case Options::Hex:
282
                writer=std::unique_ptr<OutputWriter>(new TextOutputWriter(outputFileName,TextOutputWriter::Hex));
283
                break;
284
        default:
285
                assert(false);
286
        }
287
 
288
        try {
289
                linker.link(*writer);
290
        }
291
        catch(std::exception &ex) {
292
                writer->abort();
293
                std::cerr<<"Linker error: "<<ex.what()<<std::endl;
294
                return EXIT_FAILURE;
295
        }
296
 
297
        std::cout<<writer->size()/4<<" words written"<<std::endl;
298
 
299
        if(!options.mapFileName.empty()) {
300
                std::ofstream out(options.mapFileName);
301
                if(!out) throw std::runtime_error("Cannot open file \""+options.mapFileName+"\" for writing");
302
                linker.generateMap(out);
303
        }
304
}
305
catch(std::exception &ex) {
306
        std::cerr<<"Error: "<<ex.what()<<std::endl;
307
        return EXIT_FAILURE;
308
}

powered by: WebSVN 2.1.0

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