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

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [libdbg64g/] [services/] [console/] [console.cpp] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 sergeykhbr
/**
2
 * @file
3
 * @copyright  Copyright 2016 GNSS Sensor Ltd. All right reserved.
4
 * @author     Sergey Khabarov - sergeykhbr@gmail.com
5
 * @brief      shell console class implementation.
6
 */
7
 
8
#include "console.h"
9
#include <iostream>
10
#include <stdio.h>
11
#include <string.h>
12
#include "api_types.h"
13
#include "coreservices/iserial.h"
14
 
15
namespace debugger {
16
 
17
/** Class registration in the Core */
18
REGISTER_CLASS(ConsoleService)
19
 
20
#define ENTRYSYMBOLS "riscv# "
21
 
22
static const int STDIN = 0;
23
 
24
ConsoleService::ConsoleService(const char *name)
25
    : IService(name), IHap(HAP_ConfigDone),
26
      portSerial_(this, "serialconsole", true) {
27
    registerInterface(static_cast<IThread *>(this));
28
    registerInterface(static_cast<IHap *>(this));
29
    registerInterface(static_cast<IRawListener *>(this));
30
    registerInterface(static_cast<IClockListener *>(this));
31
    registerAttribute("Enable", &isEnable_);
32
    registerAttribute("StepQueue", &stepQueue_);
33
    registerAttribute("AutoComplete", &autoComplete_);
34
    registerAttribute("CommandExecutor", &commandExecutor_);
35
    registerAttribute("Signals", &signals_);
36
    registerAttribute("InputPort", &inPort_);
37
    registerAttribute("DefaultLogFile", &defaultLogFile_);
38
 
39
    RISCV_mutex_init(&mutexConsoleOutput_);
40
    RISCV_event_create(&config_done_, "console_config_done");
41
    RISCV_register_hap(static_cast<IHap *>(this));
42
 
43
    isEnable_.make_boolean(true);
44
        stepQueue_.make_string("");
45
    autoComplete_.make_string("");
46
    commandExecutor_.make_string("");
47
        signals_.make_string("");
48
    inPort_.make_string("");
49
    defaultLogFile_.make_string("");
50
 
51
    iclk_ = NULL;
52
    isrc_ = NULL;
53
    cmdSizePrev_ = 0;
54
 
55
    cursor_.make_list(2);
56
    cursor_[0u].make_int64(0);
57
    cursor_[1].make_int64(0);
58
 
59
 
60
#ifdef DBG_ZEPHYR
61
    tst_cnt_ = 0;
62
#endif
63
 
64
#if defined(_WIN32) || defined(__CYGWIN__)
65
#else
66
    struct termios new_settings;
67
    tcgetattr(0, &original_settings_);
68
    new_settings = original_settings_;
69
 
70
    /// Disable canonical mode, and set buffer size to 1 byte
71
    new_settings.c_lflag &= ~(ICANON | ECHO);
72
    new_settings.c_cc[VTIME] = 0;
73
    new_settings.c_cc[VMIN] = 0;
74
 
75
    tcsetattr(STDIN, TCSANOW, &new_settings);
76
    term_fd_ = fileno(stdin);
77
#endif
78
    // Redirect output stream to a this console
79
    RISCV_add_default_output(static_cast<IRawListener *>(this));
80
}
81
 
82
ConsoleService::~ConsoleService() {
83
#if defined(_WIN32) || defined(__CYGWIN__)
84
#else
85
    tcsetattr(STDIN, TCSANOW, &original_settings_);
86
#endif
87
    RISCV_event_close(&config_done_);
88
    RISCV_mutex_destroy(&mutexConsoleOutput_);
89
}
90
 
91
void ConsoleService::postinitService() {
92
    ISerial *iport = static_cast<ISerial *>
93
            (RISCV_get_service_iface(inPort_.to_string(), IFACE_SERIAL));
94
    if (iport) {
95
        iport->registerRawListener(static_cast<IRawListener *>(&portSerial_));
96
    } else {
97
        RISCV_error("Can't connect to com-port %s.", inPort_.to_string());
98
    }
99
 
100
    if (isEnable_.to_bool()) {
101
        if (!run()) {
102
            RISCV_error("Can't create thread.", NULL);
103
            return;
104
        }
105
    }
106
 
107
    iclk_ = static_cast<IClock *>
108
            (RISCV_get_service_iface(stepQueue_.to_string(), IFACE_CLOCK));
109
 
110
    iautocmd_ = static_cast<IAutoComplete *>(
111
            RISCV_get_service_iface(autoComplete_.to_string(),
112
                                    IFACE_AUTO_COMPLETE));
113
    if (!iautocmd_) {
114
        RISCV_error("Can't get IAutoComplete interface %s",
115
                    autoComplete_.to_string());
116
    }
117
 
118
    iexec_ = static_cast<ICmdExecutor *>(
119
            RISCV_get_service_iface(commandExecutor_.to_string(),
120
                                    IFACE_CMD_EXECUTOR));
121
    if (!iexec_) {
122
        RISCV_error("Can't get ICmdExecutor interface %s",
123
                    commandExecutor_.to_string());
124
    }
125
 
126
    AttributeType src_list;
127
    RISCV_get_services_with_iface(IFACE_SOURCE_CODE, &src_list);
128
    if (src_list.is_list() && src_list.size()) {
129
        IService *iserv = static_cast<IService *>(src_list[0u].to_iface());
130
        isrc_ = static_cast<ISourceCode *>(
131
                    iserv->getInterface(IFACE_SOURCE_CODE));
132
    }
133
 
134
#ifdef DBG_ZEPHYR
135
    if (iclk_) {
136
            iclk_->registerStepCallback(static_cast<IClockListener *>(this), 550000);
137
            iclk_->registerStepCallback(static_cast<IClockListener *>(this), 12000000);
138
            iclk_->registerStepCallback(static_cast<IClockListener *>(this), 20000000);//6000000);
139
            iclk_->registerStepCallback(static_cast<IClockListener *>(this), 35000000);
140
        }
141
#endif
142
}
143
 
144
void ConsoleService::predeleteService() {
145
    if (isrc_) {
146
        char stmp[128];
147
        AttributeType brList, res;
148
        isrc_->getBreakpointList(&brList);
149
        for (unsigned i = 0; i < brList.size(); i++) {
150
            const AttributeType &br = brList[i];
151
            RISCV_sprintf(stmp, sizeof(stmp), "br rm 0x%" RV_PRI64 "x",
152
                           br[BrkList_address].to_uint64());
153
            iexec_->exec(stmp, &res, true);
154
        }
155
    }
156
    RISCV_remove_default_output(static_cast<IRawListener *>(this));
157
}
158
 
159
void ConsoleService::stepCallback(uint64_t t) {
160
#ifdef DBG_ZEPHYR
161
    if (iclk_ == NULL) {
162
        return;
163
    }
164
    IService *uart = static_cast<IService *>(RISCV_get_service("uart0"));
165
    if (uart) {
166
        ISerial *iserial = static_cast<ISerial *>(
167
                    uart->getInterface(IFACE_SERIAL));
168
        switch (tst_cnt_) {
169
        case 0:
170
            //iserial->writeData("ping", 4);
171
            iserial->writeData("dhry", 4);
172
            break;
173
        case 1:
174
            iserial->writeData("ticks", 5);
175
            break;
176
        case 2:
177
            iserial->writeData("help", 4);
178
            break;
179
        case 3:
180
            iserial->writeData("pnp", 4);
181
            break;
182
        default:;
183
        }
184
        tst_cnt_++;
185
    }
186
#endif
187
}
188
 
189
void ConsoleService::hapTriggered(IFace *isrc, EHapType type,
190
                                  const char *descr) {
191
    RISCV_event_set(&config_done_);
192
 
193
    // Enable logging:
194
    if (defaultLogFile_.size()) {
195
        AttributeType res;
196
        std::string cmd("log ");
197
        cmd += defaultLogFile_.to_string();
198
        iexec_->exec(cmd.c_str(), &res, true);
199
    }
200
}
201
 
202
void ConsoleService::updateData(const char *buf, int buflen) {
203
    writeBuffer(buf);
204
}
205
 
206
void ConsoleService::busyLoop() {
207
    RISCV_event_wait(&config_done_);
208
 
209
    bool cmd_ready;
210
    AttributeType cmd, cmdres;
211
 
212
    processScriptFile();
213
    while (isEnabled()) {
214
        if (!isData()) {
215
            RISCV_sleep_ms(50);
216
            continue;
217
        }
218
 
219
        cmd_ready = iautocmd_->processKey(getData(), &cmd, &cursor_);
220
        if (cmd_ready) {
221
            RISCV_mutex_lock(&mutexConsoleOutput_);
222
            std::cout << "\r";
223
            RISCV_mutex_unlock(&mutexConsoleOutput_);
224
 
225
            RISCV_printf0("%s%s", ENTRYSYMBOLS, cmd.to_string());
226
 
227
            iexec_->exec(cmd.to_string(), &cmdres, false);
228
 
229
            if (!cmdres.is_nil() && !cmdres.is_invalid()) {
230
                RISCV_printf0("%s", cmdres.to_config().to_string());
231
            }
232
        } else {
233
            RISCV_mutex_lock(&mutexConsoleOutput_);
234
            std::cout << '\r' << ENTRYSYMBOLS << cmd.to_string();
235
            if (cmdSizePrev_ > cmd.size()) {
236
                clearLine(static_cast<int>(cmdSizePrev_ - cmd.size()));
237
            }
238
            for (int i = 0; i < cursor_[0u].to_int(); i++) {
239
                std::cout << '\b';
240
            }
241
            RISCV_mutex_unlock(&mutexConsoleOutput_);
242
        }
243
        std::cout.flush();
244
        cmdSizePrev_ = cmd.size();
245
    }
246
}
247
 
248
void ConsoleService::processScriptFile() {
249
    enum EScriptState {
250
        SCRIPT_normal,
251
        SCRIPT_comment,
252
        SCRIPT_command
253
    } scr_state;
254
    scr_state = SCRIPT_normal;
255
 
256
    const AttributeType *glb = RISCV_get_global_settings();
257
    if ((*glb)["ScriptFile"].size() == 0) {
258
        return;
259
    }
260
    const char *script_name = (*glb)["ScriptFile"].to_string();
261
    FILE *script = fopen(script_name, "r");
262
    if (!script) {
263
        RISCV_error("Script file '%s' not found", script_name);
264
        return;
265
    }
266
    fseek(script, 0, SEEK_END);
267
    long script_sz = ftell(script);
268
    if (script_sz == 0) {
269
        return;
270
    }
271
    char *script_buf = new char [script_sz + 1];
272
    fseek(script, 0, SEEK_SET);
273
    fread(script_buf, 1, script_sz, script);
274
    script_buf[script_sz] = '\0';
275
    fclose(script);
276
 
277
    bool crlf = false;
278
    for (long i = 0; i < script_sz; i++) {
279
 
280
        switch (scr_state) {
281
        case SCRIPT_normal:
282
            if (crlf && script_buf[i] == '\n') {
283
                crlf = false;
284
            } else if (script_buf[i] == '/'
285
                    && script_buf[i + 1] == '/') {
286
                scr_state = SCRIPT_comment;
287
                i++;
288
            } else {
289
                //addToCommandLine(script_buf[i]);
290
            }
291
            break;
292
        case SCRIPT_command:
293
            //addToCommandLine(script_buf[i]);
294
        case SCRIPT_comment:
295
            if (script_buf[i] == '\r' || script_buf[i] == '\n') {
296
                scr_state = SCRIPT_normal;
297
            }
298
        default:;
299
        }
300
 
301
        crlf = script_buf[i] == '\r';
302
    }
303
    delete [] script_buf;
304
    RISCV_info("Script '%s' was finished", script_name);
305
}
306
 
307
void ConsoleService::writeBuffer(const char *buf) {
308
    size_t sz = strlen(buf);
309
    if (!sz) {
310
        return;
311
    }
312
    RISCV_mutex_lock(&mutexConsoleOutput_);
313
    std::cout << '\r';
314
    clearLine(70);
315
    std::cout << buf;
316
    if (buf[sz-1] != '\r' && buf[sz-1] != '\n') {
317
        std::cout << "\r\n";
318
    }
319
    std::cout << ENTRYSYMBOLS << cmdLine_.c_str();
320
    for (int i = 0; i < cursor_[0u].to_int(); i++) {
321
        std::cout << '\b';
322
    }
323
    std::cout.flush();
324
 
325
    RISCV_mutex_unlock(&mutexConsoleOutput_);
326
}
327
 
328
void ConsoleService::clearLine(int num) {
329
    for (int i = 0; i < num; i++) {
330
        std::cout << ' ';
331
    }
332
    for (int i = 0; i < num; i++) {
333
        std::cout << '\b';
334
    }
335
}
336
 
337
bool ConsoleService::isData() {
338
#if defined(_WIN32) || defined(__CYGWIN__)
339
    return _kbhit() ? true: false;
340
#else
341
    int bytesWaiting;
342
    ioctl(STDIN, FIONREAD, &bytesWaiting);
343
    return bytesWaiting != 0;
344
#endif
345
}
346
 
347
uint32_t ConsoleService::getData() {
348
    Reg64Type tbuf;
349
    tbuf.val = 0;
350
    int pos = 0;
351
    while (isData()) {
352
        tbuf.val <<= 8;
353
#if defined(_WIN32) || defined(__CYGWIN__)
354
        tbuf.buf[pos++] = static_cast<uint8_t>(_getch());
355
#else
356
        read(term_fd_, &tbuf.buf[pos], 1);
357
        pos++;
358
#endif
359
    }
360
    //printf("\nkey_code=%08x\n", tbuf.buf32[0]);
361
    switch (tbuf.buf32[0]) {
362
    case 0x000d:
363
    case 0x000a:
364
    case 0x0d0a:
365
        tbuf.buf32[0] = KB_Return;
366
        break;
367
    case 0x001b:
368
        tbuf.buf32[0] = KB_Escape;
369
        break;
370
#if defined(_WIN32) || defined(__CYGWIN__)
371
    case 0x0008:
372
        tbuf.buf32[0] = KB_Backspace;
373
        break;
374
    case VK_UP:
375
    case 0x4800:
376
        tbuf.buf32[0] = KB_Up;
377
        break;
378
    case VK_LEFT:
379
    case 0x4b00:
380
        tbuf.buf32[0] = KB_Left;
381
        break;
382
    case VK_RIGHT:
383
    case 0x4d00:
384
        tbuf.buf32[0] = KB_Right;
385
        break;
386
    case VK_DOWN:
387
    case 0x5000:
388
        tbuf.buf32[0] = KB_Down;
389
        break;
390
    case VK_DELETE:
391
    case 0x5300:
392
        tbuf.buf32[0] = KB_Delete;
393
        break;
394
    case VK_TAB:
395
    case 0x5301:
396
        tbuf.buf32[0] = KB_Tab;
397
        break;
398
#else
399
    case 0x007f:
400
        tbuf.buf32[0] = KB_Backspace;
401
        break;
402
    case 0x1b5b41:
403
    case 0x410000:
404
        tbuf.buf32[0] = KB_Up;
405
        break;
406
    case 0x1b5b44:
407
    case 0x440000:
408
        tbuf.buf32[0] = KB_Left;
409
        break;
410
    case 0x1b5b43:
411
    case 0x430000:
412
        tbuf.buf32[0] = KB_Right;
413
        break;
414
    case 0x1b5b42:
415
    case 0x420000:
416
        tbuf.buf32[0] = KB_Down;
417
        break;
418
    case 0x7e000000:
419
        tbuf.buf32[0] = KB_Delete;
420
        break;
421
    case 0x0009:
422
        tbuf.buf32[0] = KB_Tab;
423
        break;
424
#endif
425
    default:;
426
    }
427
    return tbuf.buf32[0];
428
}
429
 
430
void ConsoleService::processCommandLine() {
431
    RISCV_mutex_lock(&mutexConsoleOutput_);
432
    char tmpStr[256];
433
    char *pStr = tmpStr;
434
    if (cmdLine_.size() >= 256) {
435
        pStr = new char [cmdLine_.size() + 1];
436
    }
437
    strcpy(pStr, cmdLine_.c_str());
438
    cmdLine_.clear();
439
 
440
    std::cout << "\r\n" ENTRYSYMBOLS;
441
    RISCV_mutex_unlock(&mutexConsoleOutput_);
442
 
443
    if (pStr[0] == '\0') {
444
        return;
445
    }
446
 
447
    AttributeType t1;
448
    t1.from_config(pStr);
449
    if (t1.is_list()) {
450
        if (strcmp(t1[0u].to_string(), "wait") == 0) {
451
            RISCV_sleep_ms(static_cast<int>(t1[1].to_int64()));
452
        } else if (strcmp(t1[0u].to_string(), "uart0") == 0) {
453
            std::string strCmd(t1[1].to_string());
454
            size_t idx = strCmd.find("\\r", 0);
455
            if (idx != std::string::npos) {
456
                strCmd.replace(idx, 2, "\r");
457
            }
458
            IService *uart =
459
                static_cast<IService *>(RISCV_get_service("uart0"));
460
            if (uart) {
461
                ISerial *iserial = static_cast<ISerial *>(
462
                            uart->getInterface(IFACE_SERIAL));
463
                iserial->writeData(strCmd.c_str(),
464
                                   static_cast<int>(strCmd.size()));
465
            }
466
        }
467
    }
468
    if (pStr != tmpStr) {
469
        delete [] pStr;
470
    }
471
}
472
 
473
 
474
}  // namespace debugger

powered by: WebSVN 2.1.0

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