1 // Copyright 2017-2019 VMware, Inc.
2 // SPDX-License-Identifier: BSD-2-Clause
3 //
4 // The BSD-2 license (the License) set forth below applies to all parts of the
5 // Cascade project. You may not use this file except in compliance with the
6 // License.
7 //
8 // BSD-2 License
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include <cstring>
32 #include <signal.h>
33 #include <fstream>
34 #include <sstream>
35 #include "include/cascade.h"
36 #include "cl/cl.h"
37
38 using namespace cascade;
39 using namespace cascade::cl;
40 using namespace std;
41
42 namespace {
43
44 __attribute__((unused)) auto& g1 = Group::create("Cascade Runtime Options");
45 auto& march = StrArg<string>::create("--march")
46 .usage("sw|de10|ulx3s")
47 .description("Target architecture")
48 .initial("sw");
49 auto& fopen_dirs = StrArg<string>::create("-F")
50 .usage("<path1>:<path2>:...:<pathn>")
51 .description("Paths to search when resolving $fopen() statements")
52 .initial("");
53 auto& inc_dirs = StrArg<string>::create("-I")
54 .usage("<path1>:<path2>:...:<pathn>")
55 .description("Paths to search when resolving `include directives")
56 .initial("");
57 auto& input_path = StrArg<string>::create("-e")
58 .usage("path/to/file.v")
59 .description("Read input from file");
60
61 __attribute__((unused)) auto& g2 = Group::create("Quartus Server Options");
62 auto& quartus_host = StrArg<string>::create("--quartus_host")
63 .usage("<host>")
64 .description("Location of quartus server")
65 .initial("localhost");
66 auto& quartus_port = StrArg<uint32_t>::create("--quartus_port")
67 .usage("<port>")
68 .description("Location of quartus server")
69 .initial(9900);
70
71 __attribute__((unused)) auto& g3 = Group::create("Logging Options");
72 auto& profile = StrArg<int>::create("--profile")
73 .usage("<n>")
74 .description("Number of seconds to wait between profiling events; setting n to zero disables profiling; only effective with --enable_info")
75 .initial(0);
76 auto& enable_info = FlagArg::create("--enable_info")
77 .description("Turn on info messages");
78 auto& disable_warning = FlagArg::create("--disable_warning")
79 .description("Turn off warning messages");
80 auto& disable_error = FlagArg::create("--disable_error")
81 .description("Turn off error messages");
82 auto& enable_log = FlagArg::create("--enable_log")
83 .description("Prints debugging information to log file");
84
85 __attribute__((unused)) auto& g4 = Group::create("Optimization Options");
86 auto& disable_inlining = FlagArg::create("--disable_inlining")
87 .description("Prevents cascade from inlining modules");
88 auto& open_loop_target = StrArg<size_t>::create("--open_loop_target")
89 .usage("<n>")
90 .description("Maximum number of seconds to run in open loop for before transferring control back to runtime")
91 .initial(1);
92
93 __attribute__((unused)) auto& g5 = Group::create("REPL Options");
94 auto& disable_repl = FlagArg::create("--disable_repl")
95 .description("Disables the REPL and treats user input as stdin");
96
97 class inbuf : public streambuf {
98 public:
inbuf(streambuf * sb)99 inbuf(streambuf* sb) : streambuf() {
100 sb_ = sb;
101 prompt_ = false;
102 }
103 ~inbuf() override = default;
104
105 private:
106 streambuf* sb_;
107 bool prompt_;
108
sync()109 int sync() override {
110 return sb_->pubsync();
111 }
uflow()112 int_type uflow() override {
113 const auto res = sb_->sbumpc();
114 prompt(res);
115 prompt_ = false;
116 return res;
117 }
underflow()118 int_type underflow() override {
119 const auto res = sb_->sgetc();
120 prompt(res);
121 return res;
122 }
prompt(int_type c)123 void prompt(int_type c) {
124 if ((c == '\n') && !prompt_) {
125 prompt_ = true;
126 cout << ">>> ";
127 cout.flush();
128 }
129 }
130 };
131
132 class outbuf : public streambuf {
133 public:
outbuf(const string & color="")134 outbuf(const string& color = "") : streambuf() {
135 color_ = color;
136 }
137 ~outbuf() override = default;
138
139 private:
140 string color_;
141 stringstream ss_;
142
overflow(int_type c=traits_type::eof ())143 int_type overflow(int_type c = traits_type::eof()) override {
144 ss_.put(c);
145 if (c == '\n') {
146 ss_ << ((color_ != "") ? "\033[00m" : "") << ">>> " << color_;
147 }
148 return c;
149 }
sync()150 int_type sync() override {
151 cout << color_ << ss_.str() << ((color_ != "") ? "\033[00m" : "");
152 cout.flush();
153 ss_.str(string());
154 return 0;
155 }
156 };
157
158 // Allocate cascade on the heap so we can guarantee that it's torn down before
159 // stack or static variables.
160 Cascade* cascade_ = nullptr;
161
162 // Signal Handlers:
int_handler(int sig)163 void int_handler(int sig) {
164 (void) sig;
165 ::cascade_->request_stop();
166 }
segv_handler(int sig)167 void segv_handler(int sig) {
168 (void) sig;
169 cerr << "\033[31mCASCADE SHUTDOWN UNEXPECTEDLY\033[00m" << endl;
170 cerr << "\033[31mPlease rerun with --enable_log and forward log file to developers\033[00m" << endl;
171 exit(1);
172 }
173
174 } // namespace
175
main(int argc,char ** argv)176 int main(int argc, char** argv) {
177 // Parse command line
178 Simple::read(argc, argv);
179
180 // Wrap cin in inbuf (re-prints the prompt when the user types \n)
181 inbuf ib(cin.rdbuf());
182 cin.rdbuf(&ib);
183
184 // Install signal handlers
185 { struct sigaction action;
186 memset(&action, 0, sizeof(action));
187 action.sa_handler = ::segv_handler;
188 sigaction(SIGSEGV, &action, nullptr);
189 }
190 { struct sigaction action;
191 memset(&action, 0, sizeof(action));
192 action.sa_handler = ::int_handler;
193 sigaction(SIGINT, &action, nullptr);
194 }
195
196 // Create a new cascade
197 ::cascade_ = new Cascade();
198
199 // Set command line flags
200 ::cascade_->set_fopen_dirs(::fopen_dirs.value());
201 ::cascade_->set_include_dirs(::inc_dirs.value());
202 ::cascade_->set_enable_inlining(!::disable_inlining.value());
203 ::cascade_->set_open_loop_target(::open_loop_target.value());
204 ::cascade_->set_quartus_server(::quartus_host.value(), ::quartus_port.value());
205 ::cascade_->set_profile_interval(::profile.value());
206
207 // Map standard streams to colored outbufs
208 if (::disable_repl.value()) {
209 ::cascade_->set_stdin(cin.rdbuf());
210 }
211 ::cascade_->set_stdout(new outbuf());
212 if (!::disable_error.value()) {
213 ::cascade_->set_stderr(new outbuf("\033[31m"));
214 }
215 if (!::disable_warning.value()) {
216 ::cascade_->set_stdwarn(new outbuf("\033[33m"));
217 }
218 if (::enable_info.value()) {
219 ::cascade_->set_stdinfo(new outbuf("\033[37m"));
220 }
221 auto* fb = new filebuf();
222 if (::enable_log.value()) {
223 fb->open("cascade.log", ios::app | ios::out);
224 }
225 ::cascade_->set_stdlog(fb);
226
227 // Print the initial prompt
228 cout << ">>> ";
229
230 // Start cascade, and read the march file and -e file (if provided)
231 ::cascade_->run();
232 if (::input_path.value() != "") {
233 *::cascade_ << "`include \"share/cascade/march/" << ::march.value() << ".v\"\n"
234 << "`include \"" << ::input_path.value() << "\"" << endl;
235 } else {
236 *::cascade_ << "`include \"share/cascade/march/" << ::march.value() << ".v\"" << endl;
237 }
238 ::cascade_->stop_now();
239
240 // Switch to reading from cin if the REPL wasn't disable and wait for finish
241 if (!::disable_repl.value()) {
242 ::cascade_->rdbuf(cin.rdbuf());
243 }
244 ::cascade_->run();
245 ::cascade_->wait_for_stop();
246
247 // If cascade isn't finished by now, it's because we've caught a signal.
248 // Either way, we can delete it now.
249 if (!::cascade_->is_finished()) {
250 cerr << "\033[31mCaught Signal\033[00m" << endl;
251 }
252 delete ::cascade_;
253
254 cout << "Goodbye!" << endl;
255 return 0;
256 }
257