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

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [common/] [generic/] [cpu_generic.cpp] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 sergeykhbr
/*
2
 *  Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
3
 *
4
 *  Licensed under the Apache License, Version 2.0 (the "License");
5
 *  you may not use this file except in compliance with the License.
6
 *  You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *  Unless required by applicable law or agreed to in writing, software
11
 *  distributed under the License is distributed on an "AS IS" BASIS,
12
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *  See the License for the specific language governing permissions and
14
 *  limitations under the License.
15
 */
16
 
17
#include <api_core.h>
18
#include "cpu_generic.h"
19
#include "coreservices/isocinfo.h"
20
 
21
namespace debugger {
22
 
23
CpuGeneric::CpuGeneric(const char *name)
24
    : IService(name), IHap(HAP_ConfigDone),
25
    pc_(this, "pc", DSUREG(ureg.v.pc)),
26
    npc_(this, "npc", DSUREG(ureg.v.npc)),
27
    status_(this, "status", DSUREG(udbg.v.control)),
28
    stepping_cnt_(this, "stepping_cnt", DSUREG(udbg.v.stepping_mode_steps)),
29
    clock_cnt_(this, "clock_cnt", DSUREG(udbg.v.clock_cnt)),
30
    executed_cnt_(this, "executed_cnt", DSUREG(udbg.v.executed_cnt)),
31
    stackTraceCnt_(this, "stack_trace_cnt", DSUREG(ureg.v.stack_trace_cnt)),
32
    stackTraceBuf_(this, "stack_trace_buf", DSUREG(ureg.v.stack_trace_buf), 0),
33
    br_control_(this, "br_control", DSUREG(udbg.v.br_ctrl)),
34
    br_fetch_addr_(this, "br_fetch_addr", DSUREG(udbg.v.br_address_fetch)),
35
    br_fetch_instr_(this, "br_fetch_instr", DSUREG(udbg.v.br_instr_fetch)),
36
    br_hw_add_(this, "br_hw_add", DSUREG(udbg.v.add_breakpoint)),
37
    br_hw_remove_(this, "br_hw_remove", DSUREG(udbg.v.remove_breakpoint)) {
38
    registerInterface(static_cast<IThread *>(this));
39
    registerInterface(static_cast<IClock *>(this));
40
    registerInterface(static_cast<ICpuGeneric *>(this));
41
    registerInterface(static_cast<ICpuFunctional *>(this));
42
    registerInterface(static_cast<IResetListener *>(this));
43
    registerInterface(static_cast<IHap *>(this));
44
    registerAttribute("Enable", &isEnable_);
45
    registerAttribute("SysBus", &sysBus_);
46
    registerAttribute("DbgBus", &dbgBus_);
47
    registerAttribute("SysBusWidthBytes", &sysBusWidthBytes_);
48
    registerAttribute("SourceCode", &sourceCode_);
49
    registerAttribute("StackTraceSize", &stackTraceSize_);
50
    registerAttribute("FreqHz", &freqHz_);
51
    registerAttribute("GenerateRegTraceFile", &generateRegTraceFile_);
52
    registerAttribute("GenerateMemTraceFile", &generateMemTraceFile_);
53
    registerAttribute("ResetVector", &resetVector_);
54
    registerAttribute("SysBusMasterID", &sysBusMasterID_);
55
 
56
    char tstr[256];
57
    RISCV_sprintf(tstr, sizeof(tstr), "eventConfigDone_%s", name);
58
    RISCV_event_create(&eventConfigDone_, tstr);
59
    RISCV_register_hap(static_cast<IHap *>(this));
60
 
61
    isysbus_ = 0;
62
    estate_ = CORE_OFF;
63
    step_cnt_ = 0;
64
    pc_z_.val = 0;
65
    hw_stepping_break_ = 0;
66
    interrupt_pending_ = 0;
67
    sw_breakpoint_ = false;
68
    hw_breakpoint_ = false;
69
    skip_sw_breakpoint_ = false;
70
    hwBreakpoints_.make_list(0);
71
 
72
    dport_.valid = 0;
73
    reg_trace_file = 0;
74
    mem_trace_file = 0;
75
}
76
 
77
CpuGeneric::~CpuGeneric() {
78
    RISCV_event_close(&eventConfigDone_);
79
    if (reg_trace_file) {
80
        reg_trace_file->close();
81
        delete reg_trace_file;
82
    }
83
    if (mem_trace_file) {
84
        mem_trace_file->close();
85
        delete mem_trace_file;
86
    }
87
}
88
 
89
void CpuGeneric::postinitService() {
90
    isysbus_ = static_cast<IMemoryOperation *>(
91
        RISCV_get_service_iface(sysBus_.to_string(), IFACE_MEMORY_OPERATION));
92
    if (!isysbus_) {
93
        RISCV_error("System Bus interface '%s' not found",
94
                    sysBus_.to_string());
95
        return;
96
    }
97
 
98
    idbgbus_ = static_cast<IMemoryOperation *>(
99
        RISCV_get_service_iface(dbgBus_.to_string(), IFACE_MEMORY_OPERATION));
100
    if (!idbgbus_) {
101
        RISCV_error("Debug Bus interface '%s' not found",
102
                    dbgBus_.to_string());
103
        return;
104
    }
105
 
106
    isrc_ = static_cast<ISourceCode *>(
107
       RISCV_get_service_iface(sourceCode_.to_string(), IFACE_SOURCE_CODE));
108
    if (!isrc_) {
109
        RISCV_error("Source code interface '%s' not found",
110
                    sourceCode_.to_string());
111
        return;
112
    }
113
 
114
    stackTraceBuf_.setRegTotal(2 * stackTraceSize_.to_int());
115
 
116
    // Get global settings:
117
    const AttributeType *glb = RISCV_get_global_settings();
118
    if ((*glb)["SimEnable"].to_bool() && isEnable_.to_bool()) {
119
        if (!run()) {
120
            RISCV_error("Can't create thread.", NULL);
121
            return;
122
        }
123
        if (generateRegTraceFile_.to_bool()) {
124
            reg_trace_file = new std::ofstream("river_func_regs.log");
125
        }
126
        if (generateMemTraceFile_.to_bool()) {
127
            mem_trace_file = new std::ofstream("river_func_mem.log");
128
        }
129
    }
130
}
131
 
132
void CpuGeneric::hapTriggered(IFace *isrc, EHapType type,
133
                                       const char *descr) {
134
    RISCV_event_set(&eventConfigDone_);
135
}
136
 
137
void CpuGeneric::busyLoop() {
138
    RISCV_event_wait(&eventConfigDone_);
139
 
140
    while (isEnabled()) {
141
        updatePipeline();
142
    }
143
}
144
 
145
void CpuGeneric::updatePipeline() {
146
    if (dport_.valid) {
147
        dport_.valid = 0;
148
        updateDebugPort();
149
    }
150
 
151
    if (!updateState()) {
152
        return;
153
    }
154
 
155
    pc_.setValue(npc_.getValue());
156
    branch_ = false;
157
    oplen_ = 0;
158
 
159
    if (!checkHwBreakpoint()) {
160
        fetchILine();
161
        instr_ = decodeInstruction(cacheline_);
162
 
163
        trackContextStart();
164
        if (instr_) {
165
            oplen_ = instr_->exec(cacheline_);
166
        } else {
167
            generateIllegalOpcode();
168
        }
169
        trackContextEnd();
170
 
171
        pc_z_ = pc_.getValue();
172
    }
173
 
174
    if (!branch_) {
175
        npc_.setValue(pc_.getValue().val + oplen_);
176
    }
177
 
178
    updateQueue();
179
 
180
    handleTrap();
181
}
182
 
183
bool CpuGeneric::updateState() {
184
    bool upd = true;
185
    switch (estate_) {
186
    case CORE_OFF:
187
    case CORE_Halted:
188
        updateQueue();
189
        upd = false;
190
        break;
191
    case CORE_Stepping:
192
        if (hw_stepping_break_ <= step_cnt_) {
193
            halt("Stepping breakpoint");
194
            upd = false;
195
        }
196
        break;
197
    default:;
198
    }
199
    if (upd) {
200
        step_cnt_++;
201
    }
202
    return upd;
203
}
204
 
205
void CpuGeneric::updateQueue() {
206
    IFace *cb;
207
    queue_.initProc();
208
    queue_.pushPreQueued();
209
 
210
    while ((cb = queue_.getNext(step_cnt_)) != 0) {
211
        static_cast<IClockListener *>(cb)->stepCallback(step_cnt_);
212
    }
213
}
214
 
215
void CpuGeneric::fetchILine() {
216
    trans_.action = MemAction_Read;
217
    trans_.addr = pc_.getValue().val;
218
    trans_.xsize = 4;
219
    trans_.wstrb = 0;
220
    dma_memop(&trans_);
221
    cacheline_[0].val = trans_.rpayload.b64[0];
222
    if (skip_sw_breakpoint_ && trans_.addr == br_fetch_addr_.getValue().val) {
223
        skip_sw_breakpoint_ = false;
224
        cacheline_[0].buf32[0] = br_fetch_instr_.getValue().buf32[0];
225
    }
226
}
227
 
228
void CpuGeneric::registerStepCallback(IClockListener *cb,
229
                                               uint64_t t) {
230
    if (!isEnabled() && t <= step_cnt_) {
231
        cb->stepCallback(t);
232
        return;
233
    }
234
    queue_.put(t, cb);
235
}
236
 
237
void CpuGeneric::setBranch(uint64_t npc) {
238
    branch_ = true;
239
    npc_.setValue(npc);
240
}
241
 
242
void CpuGeneric::pushStackTrace() {
243
    int cnt = static_cast<int>(stackTraceCnt_.getValue().val);
244
    if (cnt >= stackTraceSize_.to_int()) {
245
        return;
246
    }
247
    stackTraceBuf_.write(2*cnt, pc_.getValue().val);
248
    stackTraceBuf_.write(2*cnt + 1,  npc_.getValue().val);
249
    stackTraceCnt_.setValue(cnt + 1);
250
}
251
 
252
void CpuGeneric::popStackTrace() {
253
    uint64_t cnt = stackTraceCnt_.getValue().val;
254
    if (cnt) {
255
        stackTraceCnt_.setValue(cnt - 1);
256
    }
257
}
258
 
259
void CpuGeneric::dma_memop(Axi4TransactionType *tr) {
260
    tr->source_idx = sysBusMasterID_.to_int();
261
    if (tr->xsize <= sysBusWidthBytes_.to_uint32()) {
262
        isysbus_->b_transport(tr);
263
    } else {
264
        // 1-byte access for HC08
265
        Axi4TransactionType tr1 = *tr;
266
        tr1.xsize = 1;
267
        tr1.wstrb = 1;
268
        for (unsigned i = 0; i < tr->xsize; i++) {
269
            tr1.addr = tr->addr + i;
270
            if (tr->action == MemAction_Write) {
271
                tr1.wpayload.b8[0] = tr->wpayload.b8[i];
272
            }
273
            isysbus_->b_transport(&tr1);
274
            if (tr->action == MemAction_Read) {
275
                tr->rpayload.b8[i] = tr1.rpayload.b8[0];
276
            }
277
        }
278
    }
279
    if (!mem_trace_file) {
280
    //if (!reg_trace_file) {
281
        return;
282
    }
283
 
284
    char tstr[512];
285
    Reg64Type pload = {0};
286
    if (tr->action == MemAction_Read) {
287
        if (tr->xsize == 4) {
288
            pload.buf32[0] = tr->rpayload.b32[0];
289
        } else {
290
            pload.val = tr->rpayload.b64[0];
291
        }
292
        RISCV_sprintf(tstr, sizeof(tstr),
293
                    "%08x: [%08x] => %016" RV_PRI64 "x\n",
294
                    pc_.getValue().buf32[0],
295
                    static_cast<int>(tr->addr),
296
                    pload.val);
297
    } else {
298
        if (tr->xsize == 4) {
299
            pload.buf32[0] = tr->wpayload.b32[0];
300
        } else {
301
            pload.val = tr->wpayload.b64[0];
302
        }
303
        RISCV_sprintf(tstr, sizeof(tstr),
304
                    "%08x: [%08x] <= %016" RV_PRI64 "x\n",
305
                    pc_.getValue().buf32[0],
306
                    static_cast<int>(tr->addr),
307
                    pload.val);
308
    }
309
    (*mem_trace_file) << tstr;
310
    mem_trace_file->flush();
311
}
312
 
313
void CpuGeneric::go() {
314
    if (estate_ == CORE_OFF) {
315
        RISCV_error("CPU is turned-off", 0);
316
        return;
317
    }
318
    estate_ = CORE_Normal;
319
}
320
 
321
void CpuGeneric::step() {
322
    if (estate_ == CORE_OFF) {
323
        RISCV_error("CPU is turned-off", 0);
324
        return;
325
    }
326
    hw_stepping_break_ = step_cnt_ + stepping_cnt_.getValue().val;
327
    estate_ = CORE_Stepping;
328
}
329
 
330
void CpuGeneric::halt(const char *descr) {
331
    if (estate_ == CORE_OFF) {
332
        RISCV_error("CPU is turned-off", 0);
333
        return;
334
    }
335
    char strop[32];
336
    uint8_t tbyte;
337
    unsigned bytetot = oplen_;
338
    if (!bytetot) {
339
        bytetot = 1;
340
    }
341
    for (unsigned i = 0; i < bytetot; i++) {
342
        if (endianess() == LittleEndian) {
343
            tbyte = cacheline_[0].buf[bytetot-i-1];
344
        } else {
345
            tbyte = cacheline_[0].buf[i];
346
        }
347
        RISCV_sprintf(&strop[2*i], sizeof(strop)-2*i, "%02x", tbyte);
348
    }
349
 
350
    if (descr == NULL) {
351
        RISCV_info("[%6" RV_PRI64 "d] pc:%04" RV_PRI64 "x: %s \t CPU halted",
352
                       step_cnt_, pc_.getValue().val, strop);
353
    } else {
354
        RISCV_info("[%6" RV_PRI64 "d] pc:%04" RV_PRI64 "x: %s\t %s",
355
                       step_cnt_, pc_.getValue().val, strop, descr);
356
    }
357
    estate_ = CORE_Halted;
358
    RISCV_trigger_hap(getInterface(IFACE_SERVICE), HAP_Halt, "Descr");
359
}
360
 
361
void CpuGeneric::reset(bool active) {
362
    interrupt_pending_ = 0;
363
    status_.reset(active);
364
    stackTraceCnt_.reset(active);
365
    pc_.setValue(getResetAddress());
366
    npc_.setValue(getResetAddress());
367
    if (!active && estate_ == CORE_OFF) {
368
        // Turn ON:
369
        estate_ = CORE_Halted;//CORE_Normal;
370
        RISCV_trigger_hap(static_cast<IService *>(this),
371
                            HAP_CpuTurnON, "CPU Turned ON");
372
    } else if (active) {
373
        // Turn OFF:
374
        estate_ = CORE_OFF;
375
        RISCV_trigger_hap(static_cast<IService *>(this),
376
                            HAP_CpuTurnOFF, "CPU Turned OFF");
377
    }
378
    hw_breakpoint_ = false;
379
    sw_breakpoint_ = false;
380
}
381
 
382
void CpuGeneric::updateDebugPort() {
383
    DebugPortTransactionType *trans = dport_.trans;
384
    Axi4TransactionType tr;
385
    tr.xsize = 8;
386
    tr.source_idx = 0;
387
    if (trans->write) {
388
        tr.action = MemAction_Write;
389
        tr.wpayload.b64[0] = trans->wdata;
390
        tr.wstrb = 0xFF;
391
    } else {
392
        tr.action = MemAction_Read;
393
        tr.rpayload.b64[0] = 0;
394
    }
395
    tr.addr = (static_cast<uint64_t>(trans->region) << 15) | trans->addr;
396
    idbgbus_->b_transport(&tr);
397
 
398
    trans->rdata = tr.rpayload.b64[0];;
399
    dport_.cb->nb_response_debug_port(trans);
400
}
401
 
402
void CpuGeneric::nb_transport_debug_port(DebugPortTransactionType *trans,
403
                                         IDbgNbResponse *cb) {
404
    dport_.trans = trans;
405
    dport_.cb = cb;
406
    dport_.valid = true;
407
}
408
 
409
void CpuGeneric::addHwBreakpoint(uint64_t addr) {
410
    AttributeType item;
411
    item.make_uint64(addr);
412
    hwBreakpoints_.add_to_list(&item);
413
    hwBreakpoints_.sort();
414
    for (unsigned i = 0; i < hwBreakpoints_.size(); i++) {
415
        RISCV_debug("Breakpoint[%d]: 0x%04" RV_PRI64 "x",
416
                    i, hwBreakpoints_[i].to_uint64());
417
    }
418
}
419
 
420
void CpuGeneric::removeHwBreakpoint(uint64_t addr) {
421
    for (unsigned i = 0; i < hwBreakpoints_.size(); i++) {
422
        if (addr == hwBreakpoints_[i].to_uint64()) {
423
            hwBreakpoints_.remove_from_list(i);
424
            hwBreakpoints_.sort();
425
            return;
426
        }
427
    }
428
}
429
 
430
bool CpuGeneric::checkHwBreakpoint() {
431
    uint64_t pc = pc_.getValue().val;
432
    if (hw_breakpoint_ && pc == hw_break_addr_) {
433
        hw_breakpoint_ = false;
434
        return false;
435
    }
436
    hw_breakpoint_ = false;
437
 
438
    for (unsigned i = 0; i < hwBreakpoints_.size(); i++) {
439
        uint64_t bradr = hwBreakpoints_[i].to_uint64();
440
        if (pc < bradr) {
441
            // Sorted list
442
            break;
443
        }
444
        if (pc == bradr) {
445
            hw_break_addr_ = pc;
446
            hw_breakpoint_ = true;
447
            halt("Hw breakpoint");
448
            return true;
449
        }
450
    }
451
    return false;
452
}
453
 
454
void CpuGeneric::skipBreakpoint() {
455
    skip_sw_breakpoint_ = true;
456
    sw_breakpoint_ = false;
457
}
458
 
459
 
460
uint64_t GenericStatusType::aboutToRead(uint64_t cur_val) {
461
    GenericCpuControlType ctrl;
462
    CpuGeneric *pcpu = static_cast<CpuGeneric *>(parent_);
463
    ctrl.val = 0;
464
    ctrl.bits.halt = pcpu->isHalt() || !pcpu->isOn() ? 1 : 0;
465
    ctrl.bits.sw_breakpoint = pcpu->isSwBreakpoint() ? 1 : 0;
466
    ctrl.bits.hw_breakpoint = pcpu->isHwBreakpoint() ? 1 : 0;
467
    return ctrl.val;
468
}
469
 
470
uint64_t GenericStatusType::aboutToWrite(uint64_t new_val) {
471
    GenericCpuControlType ctrl;
472
    CpuGeneric *pcpu = static_cast<CpuGeneric *>(parent_);
473
    ctrl.val = new_val;
474
    if (ctrl.bits.halt) {
475
        pcpu->halt("halted from DSU");
476
    } else if (ctrl.bits.stepping) {
477
        pcpu->step();
478
    } else {
479
        pcpu->go();
480
    }
481
    return new_val;
482
}
483
 
484
uint64_t FetchedBreakpointType::aboutToWrite(uint64_t new_val) {
485
    CpuGeneric *pcpu = static_cast<CpuGeneric *>(parent_);
486
    pcpu->skipBreakpoint();
487
    return new_val;
488
}
489
 
490
uint64_t AddBreakpointType::aboutToWrite(uint64_t new_val) {
491
    CpuGeneric *pcpu = static_cast<CpuGeneric *>(parent_);
492
    pcpu->addHwBreakpoint(new_val);
493
    return new_val;
494
}
495
 
496
uint64_t RemoveBreakpointType::aboutToWrite(uint64_t new_val) {
497
    CpuGeneric *pcpu = static_cast<CpuGeneric *>(parent_);
498
    pcpu->removeHwBreakpoint(new_val);
499
    return new_val;
500
}
501
 
502
uint64_t StepCounterType::aboutToRead(uint64_t cur_val) {
503
    CpuGeneric *pcpu = static_cast<CpuGeneric *>(parent_);
504
    return pcpu->getStepCounter();
505
}
506
 
507
}  // namespace debugger
508
 

powered by: WebSVN 2.1.0

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