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

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [libdbg64g/] [services/] [debug/] [serial_dbglink.cpp] - Rev 5

Compare with Previous | Blame | View Log

/*
 *  Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * @details
 *             Write command: 
 *                 Send     [11.Length-1].Addr[63:0].Data[31:0]*(x Length)
 *             Read command: 
 *                 Send     [10.Length-1].Addr[63:0]
 *                 Receive  Data[31:0]*(x Length)
 */
 
#include "api_core.h"
#include "serial_dbglink.h"
 
namespace debugger {
 
/** Class registration in the Core */
REGISTER_CLASS(SerialDbgService)
 
SerialDbgService::SerialDbgService(const char *name) 
    : IService(name) {
    registerInterface(static_cast<ITap *>(this));
    registerAttribute("Timeout", &timeout_);
    registerAttribute("Port", &port_);
 
    RISCV_event_create(&event_block_, "SerialDbg_event_block");
}
 
SerialDbgService::~SerialDbgService() {
    RISCV_event_close(&event_block_);
}
 
void SerialDbgService::postinitService() {
    iserial_ = static_cast<ISerial *>(
        RISCV_get_service_iface(port_.to_string(), IFACE_SERIAL));
    if (!iserial_) {
        RISCV_error("Can't find ISerial interface %s", port_.to_string());
        return;
    }
    iserial_->registerRawListener(static_cast<IRawListener *>(this));
#if 1  // hardcoded scale in tapuart, no need in clock detection
    /** Automatic baudrate definition on hardware side:
     *    [0] 0x55 - to init baud rate detector
     *    [1] 0x55 - to confirm baud rate value.
     */
    char tbuf[5] = {0x55, 0x55, 0x55, 0x55};
    iserial_->writeData(tbuf, 4);
#endif
}
 
void SerialDbgService::predeleteService() {
    if (iserial_) {
        iserial_->unregisterRawListener(static_cast<IRawListener *>(this));
    }
}
 
int SerialDbgService::read(uint64_t addr, int bytes, uint8_t *obuf) {
    if (!iserial_) {
        return TAP_ERROR;
    }
    if (bytes <= 0 || (bytes & 0x3) != 0) {
        RISCV_error("Unaligned read %d", bytes);
        return TAP_ERROR;
    }
    addr &= 0xFFFFFFFFull;
    int bytes_to_read = bytes;
    uint8_t *tout = obuf;
    pkt_.fields.magic = MAGIC_ID;
    pkt_.fields.addr = addr;
    while (bytes_to_read) {
        pkt_.fields.cmd = (0x2 << 6);
        if (bytes_to_read > 4 * UART_MST_BURST_MAX) {
            req_count_ = 4 * UART_MST_BURST_MAX;
            pkt_.fields.cmd |= 0x3F;
        } else {
            req_count_ = bytes_to_read;
            pkt_.fields.cmd |= ((bytes_to_read / 4) - 1) & 0x3F;
        }
        rd_count_ = 0;
        wait_bytes_ = req_count_;
        RISCV_event_clear(&event_block_);
        iserial_->writeData(pkt_.buf, UART_REQ_HEADER_SZ);
 
        if (RISCV_event_wait_ms(&event_block_, timeout_.to_int()) != 0) {
            RISCV_error("Reading [%08" RV_PRI64 "x] failed", addr);
            return TAP_ERROR;
        }
        if (rd_count_ != req_count_) {
            RISCV_error("Read bytes %d of %d", rd_count_, req_count_);
            return TAP_ERROR;
        }
 
        memcpy(tout, rxbuf_[0].buf, rd_count_);
        tout += rd_count_;
        pkt_.fields.addr += static_cast<unsigned>(rd_count_);
        bytes_to_read -= rd_count_;
    }
    return bytes;
}
 
int SerialDbgService::write(uint64_t addr, int bytes, uint8_t *ibuf) {
    if (!iserial_) {
        return TAP_ERROR;
    }
    if (bytes <= 0 || (bytes & 0x3) != 0) {
        RISCV_error("Unaligned write %d", bytes);
        return TAP_ERROR;
    }
    addr &= 0xFFFFFFFFull;
    int bytes_to_write = bytes;
    uint8_t *tin = ibuf;
    pkt_.fields.magic = MAGIC_ID;
    pkt_.fields.addr = addr;
    while (bytes_to_write) {
        pkt_.fields.cmd = (0x3 << 6);
        if (bytes_to_write > 4 * UART_MST_BURST_MAX) {
            req_count_ = 4 * UART_MST_BURST_MAX;
            pkt_.fields.cmd |= 0x3F;
        } else {
            req_count_ = bytes_to_write;
            pkt_.fields.cmd |= ((bytes_to_write / 4) - 1) & 0x3F;
        }
        memcpy(pkt_.fields.data, tin, req_count_);
 
        wait_bytes_ = 4;
        rd_count_ = 0;
        RISCV_event_clear(&event_block_);
        iserial_->writeData(pkt_.buf, UART_REQ_HEADER_SZ + req_count_);
 
        // Waiting "ACK\n" handshake
        if (RISCV_event_wait_ms(&event_block_, timeout_.to_int()) != 0) {
            RISCV_error("Writing [%08" RV_PRI64 "x] failed", addr);
            return TAP_ERROR;
        }
 
        tin += req_count_;
        bytes_to_write -= req_count_;
        pkt_.fields.addr += static_cast<unsigned>(req_count_);
    }
    return bytes;
}
 
void SerialDbgService::updateData(const char *buf, int buflen) {
    uint8_t *tbuf = &rxbuf_[0].buf[rd_count_];
    memcpy(tbuf, buf, buflen);
    rd_count_ += buflen;
    if (rd_count_ < wait_bytes_) {
        return;
    }
    RISCV_event_set(&event_block_);
}
 
}  // namespace debugger
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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