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 2

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

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

powered by: WebSVN 2.1.0

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