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

Subversion Repositories riscv_vhdl

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /riscv_vhdl/trunk/debugger/src/libdbg64g/services
    from Rev 4 to Rev 5
    Reverse comparison

Rev 4 → Rev 5

/.gitignore
0,0 → 1,?rev2len?
!debug
/debug/edcl.cpp
0,0 → 1,218
/**
* @file
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
* @author Sergey Khabarov - sergeykhbr@gmail.com
* @brief Access to a hardware via Ethernet EDCL interface implementaion.
*/
 
#include "edcl_types.h"
#include "edcl.h"
 
namespace debugger {
 
/** Class registration in the Core */
REGISTER_CLASS(EdclService)
 
EdclService::EdclService(const char *name) : IService(name) {
registerInterface(static_cast<ITap *>(this));
registerAttribute("Transport", &transport_);
registerAttribute("seq_cnt", &seq_cnt_);
seq_cnt_.make_uint64(0);
itransport_ = 0;
 
dbgRdTRansactionCnt_ = 0;
}
 
void EdclService::postinitService() {
IService *iserv =
static_cast<IService *>(RISCV_get_service(transport_.to_string()));
if (!iserv) {
RISCV_error("Transport service '%'s not found",
transport_.to_string());
}
itransport_ = static_cast<ILink *>(iserv->getInterface(IFACE_LINK));
if (!itransport_) {
RISCV_error("UDP interface '%s' not found",
transport_.to_string());
}
}
 
int EdclService::read(uint64_t addr, int bytes, uint8_t *obuf) {
int txoff, rxoff;
UdpEdclCommonType req = {0};
UdpEdclCommonType rsp;
 
if (!itransport_) {
RISCV_error("UDP transport not defined, addr=%x", addr);
return TAP_ERROR;
}
 
int rd_bytes = 0;
while (rd_bytes < bytes && rd_bytes != TAP_ERROR) {
req.control.request.seqidx =
static_cast<uint32_t>(seq_cnt_.to_uint64());
req.control.request.write = 0;
req.address = static_cast<uint32_t>(addr + rd_bytes);
if ((bytes - rd_bytes) > EDCL_PAYLOAD_MAX_BYTES) {
req.control.request.len =
static_cast<uint32_t>(EDCL_PAYLOAD_MAX_BYTES);
} else {
req.control.request.len = static_cast<uint32_t>(bytes - rd_bytes);
}
 
txoff = write16(tx_buf_, 0, req.offset);
txoff = write32(tx_buf_, txoff, req.control.word);
txoff = write32(tx_buf_, txoff, req.address);
 
txoff = itransport_->sendData(tx_buf_, txoff);
if (txoff == -1) {
RISCV_error("Data sending error", NULL);
rd_bytes = TAP_ERROR;
break;
}
 
dbgRdTRansactionCnt_++;
rxoff = itransport_->readData(rx_buf_, sizeof(rx_buf_));
if (rxoff == -1) {
RISCV_error("Data receiving error", NULL);
rd_bytes = TAP_ERROR;
break;
}
if (rxoff == 0) {
RISCV_error("No response. Break read transaction[%d] at %08x",
dbgRdTRansactionCnt_, req.address);
rd_bytes = TAP_ERROR;
break;
}
 
rsp.control.word = read32(&rx_buf_[2]);
 
const char *NAK[2] = {"ACK", "NAK"};
RISCV_debug("EDCL read: %s[%d], len = %d",
NAK[rsp.control.response.nak],
rsp.control.response.seqidx,
rsp.control.response.len);
 
// Retry with new sequence counter.
if (rsp.control.response.nak) {
RISCV_info("Sequence counter detected %d. Re-sending transaction.",
rsp.control.response.seqidx);
seq_cnt_.make_uint64(rsp.control.response.seqidx);
continue;
}
 
// Try to receive next packet:
if (rsp.control.response.seqidx != seq_cnt_.to_uint32()) {
RISCV_error("Wrong ID received %d != %d. Try again.",
seq_cnt_.to_uint32(), rsp.control.response.seqidx);
 
rxoff = itransport_->readData(rx_buf_, sizeof(rx_buf_));
if (rxoff <= 0) {
rd_bytes = TAP_ERROR;
break;
}
rsp.control.word = read32(&rx_buf_[2]);
if (rsp.control.response.seqidx != seq_cnt_.to_uint32()) {
rd_bytes = TAP_ERROR;
break;
}
}
 
memcpy(&obuf[rd_bytes], &rx_buf_[10], rsp.control.response.len);
rd_bytes += rsp.control.response.len;
seq_cnt_.make_uint64((seq_cnt_.to_uint64() + 1) & 0x3FFF);
}
return rd_bytes;
}
 
int EdclService::write(uint64_t addr, int bytes, uint8_t *ibuf) {
int off;
UdpEdclCommonType req = {0};
UdpEdclCommonType rsp;
 
if (!itransport_) {
RISCV_error("UDP transport not defined, addr=%x", addr);
return TAP_ERROR;
}
 
int wr_bytes = 0;
while (wr_bytes < bytes && wr_bytes != -1) {
req.control.request.seqidx =
static_cast<uint32_t>(seq_cnt_.to_uint64());
req.control.request.write = 1;
req.address = static_cast<uint32_t>(addr + wr_bytes);
if ((bytes - wr_bytes) > EDCL_PAYLOAD_MAX_BYTES) {
req.control.request.len =
static_cast<uint32_t>(EDCL_PAYLOAD_MAX_BYTES);
} else {
req.control.request.len = static_cast<uint32_t>(bytes - wr_bytes);
}
 
off = write16(tx_buf_, 0, req.offset);
off = write32(tx_buf_, off, req.control.word);
off = write32(tx_buf_, off, req.address);
memcpy(&tx_buf_[off], &ibuf[wr_bytes], req.control.request.len);
 
 
off = itransport_->sendData(tx_buf_, off + req.control.request.len);
if (off == -1) {
RISCV_error("Data sending error", NULL);
wr_bytes = -1;
break;
}
 
off = itransport_->readData(rx_buf_, sizeof(rx_buf_));
if (off == -1) {
RISCV_error("Data receiving error", NULL);
wr_bytes = -1;
break;
}
if (off == 0) {
RISCV_error("No response. Break write transaction.", NULL);
wr_bytes = -1;
break;
}
 
rsp.control.word = read32(&rx_buf_[2]);
 
// Warning:
// response length = 0;
const char *NAK[2] = {"ACK", "NAK"};
RISCV_debug("EDCL write: %s[%d], len = %d",
NAK[rsp.control.response.nak],
rsp.control.response.seqidx,
req.control.request.len);
 
// Retry with new sequence counter.
if (rsp.control.response.nak) {
RISCV_info("Sequence counter detected %d. Re-sending transaction.",
rsp.control.response.seqidx);
seq_cnt_.make_uint64(rsp.control.response.seqidx);
continue;
}
 
wr_bytes += req.control.request.len;
seq_cnt_.make_uint64(seq_cnt_.to_uint64() + 1);
}
return wr_bytes;
}
 
int EdclService::write16(uint8_t *buf, int off, uint16_t v) {
buf[off++] = (uint8_t)((v >> 8) & 0xFF);
buf[off++] = (uint8_t)(v & 0xFF);
return off;
}
 
int EdclService::write32(uint8_t *buf, int off, uint32_t v) {
buf[off++] = (uint8_t)((v >> 24) & 0xFF);
buf[off++] = (uint8_t)((v >> 16) & 0xFF);
buf[off++] = (uint8_t)((v >> 8) & 0xFF);
buf[off++] = (uint8_t)(v & 0xFF);
return off;
}
 
uint32_t EdclService::read32(uint8_t *buf) {
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
}
 
} // namespace debugger
debug/edcl.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: debug/edcl.h =================================================================== --- debug/edcl.h (nonexistent) +++ debug/edcl.h (revision 5) @@ -0,0 +1,55 @@ +/** + * @file + * @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief Access to a hardware via Ethernet EDCL interface implementaion. + */ + +#ifndef __DEBUGGER_EDCL_H__ +#define __DEBUGGER_EDCL_H__ + +#include "iclass.h" +#include "iservice.h" +#include "coreservices/itap.h" +#include "coreservices/ilink.h" +#include + +namespace debugger { + +class EdclService : public IService, + public ITap { +public: + EdclService(const char *name); + + /** IService interface */ + virtual void postinitService(); + + /** ITap interface */ + virtual int read(uint64_t addr, int bytes, uint8_t *obuf); + virtual int write(uint64_t addr, int bytes, uint8_t *ibuf); + +private: + int write16(uint8_t *buf, int off, uint16_t v); + int write32(uint8_t *buf, int off, uint32_t v); + uint32_t read32(uint8_t *buf); + +private: + /** This is limitation of the MAC fifo. Protocol allows increase the + * following value up to 242 words. */ + static const int EDCL_PAYLOAD_MAX_WORDS32 = 8; + static const int EDCL_PAYLOAD_MAX_BYTES = 4*EDCL_PAYLOAD_MAX_WORDS32; + + uint8_t tx_buf_[4096]; + uint8_t rx_buf_[4096]; + ILink *itransport_; + AttributeType transport_; + AttributeType seq_cnt_; + + int dbgRdTRansactionCnt_; +}; + +DECLARE_CLASS(EdclService) + +} // namespace debugger + +#endif // __DEBUGGER_EDCL_H__
debug/edcl.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: debug/edcl_types.h =================================================================== --- debug/edcl_types.h (nonexistent) +++ debug/edcl_types.h (revision 5) @@ -0,0 +1,49 @@ +/** + * @file + * @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief EDCL user defined transport structure. + */ + + #ifndef __DEBUGGER_EDCL_TYPES_H__ + #define __DEBUGGER_EDCL_TYPES_H__ + + #include + + namespace debugger { + +struct EdclControlRequestType { + // 32 bits fields: + uint32_t unused : 7; + uint32_t len : 10; + uint32_t write : 1; // read = 0; write = 1 + uint32_t seqidx : 14; // sequence id + //uint32 data; // 0 to 242 words +}; + + +struct EdclControlResponseType { + // 32 bits fields: + uint32_t unused : 7; + uint32_t len : 10; + uint32_t nak : 1; // ACK = 0; NAK = 1 + uint32_t seqidx : 14; // sequence id + //uint32 data; // 0 to 242 words +}; + +#pragma pack(1) +struct UdpEdclCommonType { + uint16_t offset; + union ControlType { + uint32_t word; + EdclControlRequestType request; + EdclControlResponseType response; + } control; + uint32_t address; + //uint32 data; // 0 to 242 words +}; +#pragma pack() + +} // namespace debugger + +#endif // __DEBUGGER_EDCL_TYPES_H__
debug/edcl_types.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: debug/serial_dbglink.cpp =================================================================== --- debug/serial_dbglink.cpp (nonexistent) +++ debug/serial_dbglink.cpp (revision 5) @@ -0,0 +1,165 @@ +/* + * 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(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( + 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(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(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(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(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
debug/serial_dbglink.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: debug/serial_dbglink.h =================================================================== --- debug/serial_dbglink.h (nonexistent) +++ debug/serial_dbglink.h (revision 5) @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#ifndef __DEBUGGER_SERIAL_DBGLINK_SERVICE_H__ +#define __DEBUGGER_SERIAL_DBGLINK_SERVICE_H__ + +#include "iclass.h" +#include "iservice.h" +#include "coreservices/itap.h" +#include "coreservices/iserial.h" +#include "coreservices/irawlistener.h" + +namespace debugger { + +#define MAGIC_ID 0x31 +static const int UART_REQ_HEADER_SZ = 10; +static const int UART_MST_BURST_MAX = 64; + +#pragma pack(1) +struct UartMstPacketType { + uint8_t magic; + uint8_t cmd; + uint64_t addr; + uint32_t data[UART_MST_BURST_MAX]; +}; +#pragma pack() + +union PacketType { + UartMstPacketType fields; + char buf[1]; +}; + +class SerialDbgService : public IService, + public ITap, + public IRawListener { +public: + SerialDbgService(const char *name); + ~SerialDbgService(); + + /** IService interface */ + virtual void postinitService(); + virtual void predeleteService(); + + /** ITap interface */ + virtual int read(uint64_t addr, int bytes, uint8_t *obuf); + virtual int write(uint64_t addr, int bytes, uint8_t *ibuf); + + /** IRawListener interface */ + virtual void updateData(const char *buf, int buflen); + +private: + AttributeType timeout_; + AttributeType port_; + + ISerial *iserial_; + event_def event_block_; + PacketType pkt_; + int rd_count_; + int req_count_; + int wait_bytes_; + Reg64Type rxbuf_[UART_MST_BURST_MAX]; +}; + +DECLARE_CLASS(SerialDbgService) + +} // namespace debugger + +#endif // __DEBUGGER_SERIAL_DBGLINK_SERVICE_H__
debug/serial_dbglink.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: debug/udp_dbglink.cpp =================================================================== --- debug/udp_dbglink.cpp (nonexistent) +++ debug/udp_dbglink.cpp (revision 5) @@ -0,0 +1,259 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief UDP transport level implementation. + */ + +#include "api_core.h" +#include "udp_dbglink.h" + +namespace debugger { + +/** Class registration in the Core */ +REGISTER_CLASS(UdpService) + +UdpService::UdpService(const char *name) + : IService(name) { + registerInterface(static_cast(this)); + registerAttribute("Timeout", &timeout_); + registerAttribute("BlockingMode", &blockmode_); + registerAttribute("HostIP", &hostIP_); + registerAttribute("BoardIP", &boardIP_); + + timeout_.make_int64(0); + blockmode_.make_boolean(true); + hostIP_.make_string("192.168.0.53"); + boardIP_.make_string("192.168.0.51"); +} + +UdpService::~UdpService() { + closeDatagramSocket(); +} + +void UdpService::postinitService() { + createDatagramSocket(); + // define hardcoded remote address: + remote_sockaddr_ipv4_ = sockaddr_ipv4_; + remote_sockaddr_ipv4_.sin_addr.s_addr = inet_addr(boardIP_.to_string()); + + if (timeout_.to_int64()) { + struct timeval tv; +#if defined(_WIN32) || defined(__CYGWIN__) + /** On windows timeout of the setsockopt() function is the DWORD + * size variable in msec, so we use only the first field in timeval + * struct and directly assgign argument. + */ + tv.tv_usec = 0; + tv.tv_sec = static_cast(timeout_.to_int64()); +#else + tv.tv_usec = (timeout_.to_int64() % 1000) * 1000; + tv.tv_sec = static_cast(timeout_.to_int64()/1000); +#endif + + setsockopt(hsock_, SOL_SOCKET, SO_RCVTIMEO, + (char *)&tv, sizeof(struct timeval)); + } + + /** By default socket was created with Blocking mode */ + if (!blockmode_.to_bool()) { + setBlockingMode(false); + } +} + +int UdpService::createDatagramSocket() { + char hostName[256]; + if (gethostname(hostName, sizeof(hostName)) < 0) { + return -1; + } + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + /** + * Check availability of IPv4 address assigned via attribute 'hostIP'. + * If it woudn't be found use the last avaialble IP address. + */ + bool host_ip_found = false; + int retval; + struct addrinfo *result = NULL; + struct addrinfo *ptr = NULL; + retval = getaddrinfo(hostName, "0", &hints, &result); + if (retval != 0) { + return -1; + } + + for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { + // Find only IPV4 address, ignore others. + if (ptr->ai_family != AF_INET) { + continue; + } + sockaddr_ipv4_ = *((struct sockaddr_in *)ptr->ai_addr); + RISCV_sprintf(sockaddr_ipv4_str_, sizeof(sockaddr_ipv4_str_), + "%s", inet_ntoa(sockaddr_ipv4_.sin_addr)); + + if (strcmp(inet_ntoa(sockaddr_ipv4_.sin_addr), + hostIP_.to_string()) == 0) { + host_ip_found = true; + break; + } + } + + if (!host_ip_found) { + RISCV_info("Selected IPv4 %s", inet_ntoa(sockaddr_ipv4_.sin_addr)); + } else { +#if 1 + /** jrkk proposal to hardcode IP address in a such way. No difference. */ + memset(&sockaddr_ipv4_, 0, sizeof (sockaddr_ipv4_)); + sockaddr_ipv4_.sin_family = AF_INET; + inet_pton(AF_INET, hostIP_.to_string(), &(sockaddr_ipv4_.sin_addr)); +#endif + } + + hsock_ = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (hsock_ < 0) { + RISCV_error("%s", "Error: socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)"); + return -1; + } + + int res = bind(hsock_, (struct sockaddr *)&sockaddr_ipv4_, + sizeof(sockaddr_ipv4_)); + if (res != 0) { + RISCV_error("Error: bind(hsock_, \"%s\", ...)", hostIP_.to_string()); + return -1; + } + + addr_size_t addr_sz = sizeof(sockaddr_ipv4_); + res = getsockname(hsock_, (struct sockaddr *)&sockaddr_ipv4_, &addr_sz); + sockaddr_ipv4_port_ = ntohs(sockaddr_ipv4_.sin_port); + + RISCV_info("\tIPv4 address %s:%d . . . opened", + sockaddr_ipv4_str_, sockaddr_ipv4_port_); + + return 0; +} + +void UdpService::closeDatagramSocket() { + if (hsock_ < 0) + return; + +#if defined(_WIN32) || defined(__CYGWIN__) + closesocket(hsock_); +#else + shutdown(hsock_, SHUT_RDWR); + close(hsock_); +#endif + hsock_ = -1; +} + +void UdpService::getConnectionSettings(AttributeType *settings) { + settings->make_dict(); + (*settings)["IP"] = AttributeType(inet_ntoa(sockaddr_ipv4_.sin_addr)); + (*settings)["Port"] = AttributeType(Attr_UInteger, + static_cast(sockaddr_ipv4_.sin_port)); +} + +void UdpService::setConnectionSettings(const AttributeType *target) { + if (!target->is_dict()) { + return; + } + remote_sockaddr_ipv4_.sin_addr.s_addr = + inet_addr((*target)["IP"].to_string()); + remote_sockaddr_ipv4_.sin_port = + static_cast((*target)["Port"].to_uint64()); +} + +bool UdpService::setBlockingMode(bool mode) { + int ret; +#if defined(_WIN32) || defined(__CYGWIN__) + u_long arg = mode ? 0 : 1; + ret = ioctlsocket(hsock_, FIONBIO, &arg); +#else + int flags = fcntl(hsock_, F_GETFL, 0); + if (flags < 0) { + return false; + } + flags = mode ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + ret = fcntl(hsock_, F_SETFL, flags); +#endif + if (ret == 0) { + // success + blockmode_.make_boolean(mode); + return true; + } + return false; +} + +int UdpService::sendData(const uint8_t *msg, int len) { + int tx_bytes = sendto(hsock_, reinterpret_cast(msg), len, 0, + reinterpret_cast(&remote_sockaddr_ipv4_), + static_cast(sizeof(remote_sockaddr_ipv4_))); + + if (tx_bytes < 0) { +#if defined(_WIN32) || defined(__CYGWIN__) + RISCV_error("sendto() failed with error: %d\n", WSAGetLastError()); +#else + RISCV_error("sendto() failed\n", NULL); +#endif + return 1; + } else if (logLevel_.to_int() >= LOG_DEBUG) { + char dbg[1024]; + int pos = RISCV_sprintf(dbg, sizeof(dbg), "send %d bytes to %s:%d: ", + tx_bytes, + inet_ntoa(remote_sockaddr_ipv4_.sin_addr), + ntohs(remote_sockaddr_ipv4_.sin_port)); + + if (tx_bytes < 64) { + for (int i = 0; i < len; i++) { + pos += RISCV_sprintf(&dbg[pos], sizeof(dbg) - pos, + "%02x", msg[i] & 0xFF); + } + } + RISCV_debug("%s", dbg); + } + return tx_bytes; +} + +int UdpService::readData(const uint8_t *buf, int maxlen) { + int sockerr; + addr_size_t sockerr_len = sizeof(sockerr); + addr_size_t addr_sz = sizeof(sockaddr_ipv4_); + + int res = recvfrom(hsock_, rcvbuf, sizeof(rcvbuf), + 0, (struct sockaddr *)&sockaddr_ipv4_, &addr_sz); + getsockopt(hsock_, SOL_SOCKET, SO_ERROR, + (char *)&sockerr, &sockerr_len); + + if (res < 0 && sockerr < 0) { + RISCV_error("Socket error %x", sockerr); + res = -1; + } else if (res < 0 && sockerr == 0) { + // Timeout: + res = 0; + } else if (res > 0) { + if (maxlen < res) { + res = maxlen; + RISCV_error("Receiver's buffer overflow maxlen = %d", maxlen); + } + memcpy(const_cast(buf), rcvbuf, res); + + if (logLevel_.to_int() >= LOG_DEBUG) { + char dbg[1024]; + int pos = RISCV_sprintf(dbg, sizeof(dbg), + "received %d Bytes: ", res); + if (res < 64) { + for (int i = 0; i < res; i++) { + pos += RISCV_sprintf(&dbg[pos], sizeof(dbg) - pos, + "%02x", rcvbuf[i] & 0xFF); + } + } + RISCV_debug("%s", dbg); + } + } + return res; +} + +} // namespace debugger
debug/udp_dbglink.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: debug/udp_dbglink.h =================================================================== --- debug/udp_dbglink.h (nonexistent) +++ debug/udp_dbglink.h (revision 5) @@ -0,0 +1,56 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief UDP transport level implementation. + */ + +#ifndef __DEBUGGER_UDP_DBGLINK_SERVICE_H__ +#define __DEBUGGER_UDP_DBGLINK_SERVICE_H__ + +#include "iclass.h" +#include "iservice.h" +#include "coreservices/ilink.h" +#include "coreservices/itap.h" + +namespace debugger { + +class UdpService : public IService, + public ILink { +public: + UdpService(const char *name); + ~UdpService(); + + /** IService interface */ + virtual void postinitService(); + + /** ILink interface */ + virtual void getConnectionSettings(AttributeType *settings); + virtual void setConnectionSettings(const AttributeType *target); + virtual int sendData(const uint8_t *msg, int len); + virtual int readData(const uint8_t *buf, int maxlen); + +protected: + int createDatagramSocket(); + void closeDatagramSocket(); + bool setBlockingMode(bool mode); + +private: + AttributeType timeout_; + AttributeType blockmode_; + AttributeType hostIP_; + AttributeType boardIP_; + + struct sockaddr_in sockaddr_ipv4_; + char sockaddr_ipv4_str_[16]; // 3 dots + 4 digits each 3 symbols + '\0' = 4*3 + 3 + 1; + unsigned short sockaddr_ipv4_port_; + struct sockaddr_in remote_sockaddr_ipv4_; + socket_def hsock_; + char rcvbuf[4096]; +}; + +DECLARE_CLASS(UdpService) + +} // namespace debugger + +#endif // __DEBUGGER_UDP_DBGLINK_SERVICE_H__
debug/udp_dbglink.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: exec/cmd/cmd_loadbin.cpp =================================================================== --- exec/cmd/cmd_loadbin.cpp (nonexistent) +++ exec/cmd/cmd_loadbin.cpp (revision 5) @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#include "iservice.h" +#include "cmd_loadbin.h" +#include + +namespace debugger { + +CmdLoadBin::CmdLoadBin(ITap *tap, ISocInfo *info) + : ICommand ("loadbin", tap, info) { + + briefDescr_.make_string("Load binary file"); + detailedDescr_.make_string( + "Description:\n" + " Load BIN-file to SOC target memory with specified address.\n" + "Example:\n" + " loadsrec /home/hc08/image.bin 0x04000\n"); +} + +bool CmdLoadBin::isValid(AttributeType *args) { + if ((*args)[0u].is_equal("loadbin") + && args->size() == 3) { + return CMD_VALID; + } + return CMD_INVALID; +} + +void CmdLoadBin::exec(AttributeType *args, AttributeType *res) { + res->make_nil(); + if (!isValid(args)) { + generateError(res, "Wrong argument list"); + return; + } + + const char *filename = (*args)[1].to_string(); + FILE *fp = fopen(filename, "rb"); + if (!fp) { + generateError(res, "File not found"); + return; + } + fseek(fp, 0, SEEK_END); + int sz = ftell(fp); + rewind(fp); + uint8_t *image = new uint8_t[sz]; + fread(image, 1, sz, fp); + fclose(fp); + + uint64_t addr = (*args)[2].to_uint64(); + tap_->write(addr, sz, image); + delete [] image; +} + +} // namespace debugger
exec/cmd/cmd_loadbin.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: exec/cmd/cmd_loadbin.h =================================================================== --- exec/cmd/cmd_loadbin.h (nonexistent) +++ exec/cmd/cmd_loadbin.h (revision 5) @@ -0,0 +1,30 @@ +/** + * @file + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief Binary-file loader command. + */ + +#ifndef __DEBUGGER_SERVICES_EXEC_CMD_LOADBIN_H__ +#define __DEBUGGER_SERVICES_EXEC_CMD_LOADBIN_H__ + +#include "api_core.h" +#include "coreservices/itap.h" +#include "coreservices/isocinfo.h" +#include "coreservices/icommand.h" + +namespace debugger { + +class CmdLoadBin : public ICommand { + public: + explicit CmdLoadBin(ITap *tap, ISocInfo *info); + + /** ICommand interface */ + virtual bool isValid(AttributeType *args); + virtual void exec(AttributeType *args, AttributeType *res); + + private: +}; + +} // namespace debugger + +#endif // __DEBUGGER_SERVICES_EXEC_CMD_LOADBIN_H__
exec/cmd/cmd_loadbin.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: exec/cmd/cmd_loadsrec.cpp =================================================================== --- exec/cmd/cmd_loadsrec.cpp (nonexistent) +++ exec/cmd/cmd_loadsrec.cpp (revision 5) @@ -0,0 +1,252 @@ +/** + * @file + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief SREC-file loader command. + */ + +#include "iservice.h" +#include "cmd_loadsrec.h" +#include + +namespace debugger { + +//#define SHOW_USAGE_INFO + +#ifdef SHOW_USAGE_INFO +#define ADDR_SPACE (1 << 16) +char mark_[ADDR_SPACE] = {0}; + +void mark_addr(uint64_t addr, int len) { + for (int i = 0; i < len; i++) { + if ((addr + i) >= ADDR_SPACE) { + continue; + } + mark_[addr + i] = 1; + } +} + +bool is_flash(unsigned addr) { + if (addr >= 0x0450 && addr < 0x0500) { + return true; + } + if (addr >= 0x0580 && addr < 0x0600) { + return true; + } + if (addr >= 0x0E00 && addr < 0xfe00) { + return true; + } + return false; +} + +void print_flash_usage() { + unsigned start_addr = 0; + int cnt = 0; + int total_cnt = 0; + + RISCV_printf(NULL, 0, "!!! Free Flash regions:", NULL); + for (unsigned i = 0; i < ADDR_SPACE; i++) { + if (!is_flash(i)) { + if (cnt != 0) { + RISCV_printf(NULL, 0, " [%04x..%04x], length %d B", + start_addr, (start_addr + cnt - 1), cnt); + total_cnt += cnt; + cnt = 0; + } + continue; + } + + if (mark_[i]) { + if (cnt != 0) { + RISCV_printf(NULL, 0, " [%04x..%04x], length %d B", + start_addr, (start_addr + cnt - 1), cnt); + total_cnt += cnt; + cnt = 0; + } + continue; + } + if (cnt == 0) { + start_addr = i; + } + cnt++; + } + + RISCV_printf(NULL, 0, " =========================", NULL); + RISCV_printf(NULL, 0, " Total: %d B", total_cnt); +} +#endif + +CmdLoadSrec::CmdLoadSrec(ITap *tap, ISocInfo *info) + : ICommand ("loadsrec", tap, info) { + + briefDescr_.make_string("Load SREC-file"); + detailedDescr_.make_string( + "Description:\n" + " Load SREC-file to SOC target memory.\n" + "Example:\n" + " loadsrec /home/hc08/image.s19\n"); +} + +bool CmdLoadSrec::isValid(AttributeType *args) { + if ((*args)[0u].is_equal("loadsrec") + && (args->size() == 2 || args->size() == 3)) { + return CMD_VALID; + } + return CMD_INVALID; +} + +void CmdLoadSrec::exec(AttributeType *args, AttributeType *res) { + res->make_nil(); + if (!isValid(args)) { + generateError(res, "Wrong argument list"); + return; + } + + const char *filename = (*args)[1].to_string(); + FILE *fp = fopen(filename, "rb"); + if (!fp) { + generateError(res, "File not found"); + return; + } + fseek(fp, 0, SEEK_END); + int sz = ftell(fp); + rewind(fp); + uint8_t *image = new uint8_t[sz]; + fread(image, 1, sz, fp); + fclose(fp); + + int off = check_header(image); + + DsuMapType *dsu = info_->getpDsu(); + uint64_t soft_reset = 1; + uint64_t addr = reinterpret_cast(&dsu->ulocal.v.soft_reset); + tap_->write(addr, 8, reinterpret_cast(&soft_reset)); + + uint64_t sec_addr; + int sec_sz; + uint8_t sec_data[1024]; + while ((off = readline(image, off, sec_addr, sec_sz, sec_data)) != 0) { + tap_->write(sec_addr, sec_sz, sec_data); +#ifdef SHOW_USAGE_INFO + mark_addr(sec_addr, sec_sz); +#endif + } + +// soft_reset = 0; +// tap_->write(addr, 8, reinterpret_cast(&soft_reset)); + delete [] image; + +#ifdef SHOW_USAGE_INFO + print_flash_usage(); +#endif +} + +uint8_t CmdLoadSrec::str2byte(uint8_t *pair) { + uint8_t ret = 0; + for (int i = 0; i < 2; i++) { + ret <<= 4; + if (pair[i] >= '0' && pair[i] <= '9') { + ret |= pair[i] - '0'; + } else if (pair[i] >= 'A' && pair[i] <= 'F') { + ret |= pair[i] - 'A' + 10; + } else if (pair[i] >= 'a' && pair[i] <= 'f') { + ret |= pair[i] - 'a' + 10; + } + } + return ret; +} + +bool CmdLoadSrec::check_crc(uint8_t *str, int sz) { + uint8_t sum = 0; + uint8_t *cur = str; + for (int i = 0; i < sz; i++) { + sum += str2byte(cur); + cur += 2; + } + sum = ~sum; + uint8_t ctrl = str2byte(cur); + return ctrl == sum; +} + +int CmdLoadSrec::check_header(uint8_t *img) { + int off = 2; + if (img[0] != 'S' || img[1] != '0') { + return 0; + } + uint8_t sz = str2byte(&img[off]); + if (!check_crc(&img[off], sz)) { + return 0; + } + + off += 2; + uint16_t addr = str2byte(&img[off]); + off += 2; + addr = (addr << 8) + str2byte(&img[off]); + off += 2; + if (addr != 0) { + return 0; + } + for (int i = 0; i < sz - 3; i++) { // size (1) + addr (2) = 3 + header_data_[i] = static_cast(str2byte(&img[off])); + header_data_[i + 1] = 0; + off += 2; + } + off += 2; // skip checksum + if (img[off] != '\r' || img[off + 1] != '\n') { + return 0; + } + return off + 2; +} + +int CmdLoadSrec::readline(uint8_t *img, int off, + uint64_t &addr, int &sz, uint8_t *out) { + if (img[off++] != 'S') { + return 0; + } + int bytes4addr = 0; + switch (img[off++]) { // 16-bits address only + case '1': + bytes4addr = 2; // 16-bits address + break; + case '2': + bytes4addr = 3; // 24-bits address + break; + case '3': + bytes4addr = 4; // 32-bits address + break; + default: + return 0; + } + sz = str2byte(&img[off]); + if (!check_crc(&img[off], sz)) { + return 0; + } + sz -= 1; + off += 2; + + addr = 0; + for (int i = 0; i < bytes4addr; i++) { + addr <<= 8; + addr += str2byte(&img[off]); + off += 2; + sz--; + } +#if 1 + // MCU specific endcoding: + if (bytes4addr == 3) { + uint64_t page = addr >> 16; + addr = (0x4000 * page) + (addr & 0x3FFF); + } +#endif + + for (int i = 0; i < sz; i++) { + out[i] = static_cast(str2byte(&img[off])); + off += 2; + } + off += 2; // skip checksum + if (img[off] != '\r' || img[off + 1] != '\n') { + return 0; + } + return off + 2; +} + +} // namespace debugger
exec/cmd/cmd_loadsrec.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: exec/cmd/cmd_loadsrec.h =================================================================== --- exec/cmd/cmd_loadsrec.h (nonexistent) +++ exec/cmd/cmd_loadsrec.h (revision 5) @@ -0,0 +1,38 @@ +/** + * @file + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief SREC-file loader command. + */ + +#ifndef __DEBUGGER_CMD_LOADSREC_H__ +#define __DEBUGGER_CMD_LOADSREC_H__ + +#include "api_core.h" +#include "coreservices/itap.h" +#include "coreservices/isocinfo.h" +#include "coreservices/icommand.h" + +namespace debugger { + +class CmdLoadSrec : public ICommand { +public: + explicit CmdLoadSrec(ITap *tap, ISocInfo *info); + + /** ICommand interface */ + virtual bool isValid(AttributeType *args); + virtual void exec(AttributeType *args, AttributeType *res); + +private: + uint8_t str2byte(uint8_t *pair); + bool check_crc(uint8_t *str, int sz); + int check_header(uint8_t *img); + int readline(uint8_t *img, int off, + uint64_t &addr, int &sz, uint8_t *out); + +private: + char header_data_[1024]; +}; + +} // namespace debugger + +#endif // __DEBUGGER_CMD_LOADSREC_H__
exec/cmd/cmd_loadsrec.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: remote/tcpclient.cpp =================================================================== --- remote/tcpclient.cpp (nonexistent) +++ remote/tcpclient.cpp (revision 5) @@ -0,0 +1,126 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief Remote access to debugger via TCP connection. Client thread. + */ + +#include "tcpclient.h" + +namespace debugger { + +/** Class registration in the Core */ +REGISTER_CLASS(TcpClient) + +TcpClient::TcpClient(const char *name) : IService(name), + tcpcmd_(static_cast(this)) { + registerInterface(static_cast(this)); + registerAttribute("Enable", &isEnable_); + RISCV_mutex_init(&mutexTx_); +} + +TcpClient::~TcpClient() { + RISCV_mutex_destroy(&mutexTx_); +} + +void TcpClient::postinitService() { + if (isEnable_.to_bool()) { + if (!run()) { + RISCV_error("Can't create thread.", NULL); + return; + } + } +} + +void TcpClient::updateData(const char *buf, int buflen) { + AttributeType console; + console.make_list(2); + console[0u].make_string("Console"); + console[1].make_string(buf); + console.to_config(); + + RISCV_mutex_lock(&mutexTx_); + memcpy(&txbuf_[txcnt_], console.to_string(), console.size() + 1); + txcnt_ += console.size() + 1; + RISCV_mutex_unlock(&mutexTx_); +} + +void TcpClient::busyLoop() { + int rxbytes; + int sockerr; + addr_size_t sockerr_len = sizeof(sockerr); + RISCV_add_default_output(static_cast(this)); + + cmdcnt_ = 0; + txcnt_ = 0; + while (isEnabled()) { + rxbytes = recv(hsock_, rcvbuf, sizeof(rcvbuf), 0); + getsockopt(hsock_, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&sockerr), &sockerr_len); + + if (rxbytes == 0) { + RISCV_error("Socket error: rxbytes=%d, sockerr=%d", + rxbytes, sockerr); + loopEnable_.state = false; + } else if (rxbytes < 0) { + // Timeout: + } else if (rxbytes > 0) { + for (int i = 0; i < rxbytes; i++) { + cmdbuf_[cmdcnt_++] = rcvbuf[i]; + if (rcvbuf[i] == '\0') { + processRxString(); + cmdcnt_ = 0; + } + } + } + if (sendTxBuf() < 0) { + RISCV_error("Send error: txcnt=%d", txcnt_); + loopEnable_.state = false; + } + } + closeSocket(); + RISCV_remove_default_output(static_cast(this)); +} + +void TcpClient::processRxString() { + tcpcmd_.updateData(cmdbuf_, cmdcnt_); + AttributeType *resp = tcpcmd_.response(); + RISCV_mutex_lock(&mutexTx_); + memcpy(&txbuf_[txcnt_], resp->to_string(), resp->size() + 1); + txcnt_ += resp->size() + 1; + RISCV_mutex_unlock(&mutexTx_); +} + +int TcpClient::sendTxBuf() { + int total = txcnt_; + char *ptx = txbuf_; + int txbytes; + while (total > 0) { + txbytes = send(hsock_, ptx, total, 0); + if (txbytes == 0) { + return -1; + } + total -= txbytes; + ptx += txbytes; + } + RISCV_mutex_lock(&mutexTx_); + txcnt_ = 0; + RISCV_mutex_unlock(&mutexTx_); + return 0; +} + +void TcpClient::closeSocket() { + if (hsock_ < 0) { + return; + } + +#if defined(_WIN32) || defined(__CYGWIN__) + closesocket(hsock_); +#else + shutdown(hsock_, SHUT_RDWR); + close(hsock_); +#endif + hsock_ = -1; +} + +} // namespace debugger
remote/tcpclient.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: remote/tcpclient.h =================================================================== --- remote/tcpclient.h (nonexistent) +++ remote/tcpclient.h (revision 5) @@ -0,0 +1,62 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief Remote access to debugger via TCP connection. Client thread. + */ + +#ifndef __DEBUGGER_TCPCLIENT_H__ +#define __DEBUGGER_TCPCLIENT_H__ + +#include +#include +#include "tcpcmd.h" +#include "coreservices/ithread.h" +#include "coreservices/irawlistener.h" + +namespace debugger { + +class TcpClient : public IService, + public IThread, + public IRawListener { + public: + explicit TcpClient(const char *name); + virtual ~TcpClient(); + + /** IService interface */ + virtual void postinitService(); + virtual void setExtArgument(void *args) { + hsock_ = *reinterpret_cast(args); + } + + /** IRawListener interface */ + virtual void updateData(const char *buf, int buflen); + + protected: + /** IThread interface */ + virtual void busyLoop(); + + protected: + void processRxString(); + int sendTxBuf(); + void closeSocket(); + + private: + AttributeType isEnable_; + AttributeType timeout_; + socket_def hsock_; + mutex_def mutexTx_; + char rcvbuf[4096]; + char cmdbuf_[4096]; + int cmdcnt_; + char txbuf_[1<<20]; + int txcnt_; + + TcpCommands tcpcmd_; +}; + +DECLARE_CLASS(TcpClient) + +} // namespace debugger + +#endif // __DEBUGGER_TCPCLIENT_H__
remote/tcpclient.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: remote/tcpcmd.cpp =================================================================== --- remote/tcpcmd.cpp (nonexistent) +++ remote/tcpcmd.cpp (revision 5) @@ -0,0 +1,310 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief TCP commands parser/processor. + */ + +#include "tcpcmd.h" + +namespace debugger { + +TcpCommands::TcpCommands(IService *parent) : IHap(HAP_All) { + parent_ = parent; + rxcnt_ = 0; + + cpu_.make_string("core0"); + executor_.make_string("cmdexec0"); + source_.make_string("src0"); + + iexec_ = static_cast( + RISCV_get_service_iface(executor_.to_string(), IFACE_CMD_EXECUTOR)); + + iclk_ = static_cast( + RISCV_get_service_iface(cpu_.to_string(), IFACE_CLOCK)); + IService *iservcpu = static_cast( + RISCV_get_service(cpu_.to_string())); + cpuLogLevel_ = static_cast( + iservcpu->getAttribute("LogLevel")); + + iriscv_ = static_cast( + RISCV_get_service_iface(cpu_.to_string(), IFACE_CPU_RISCV)); + + isrc_ = static_cast( + RISCV_get_service_iface(source_.to_string(), IFACE_SOURCE_CODE)); + + char tstr[128]; + RISCV_sprintf(tstr, sizeof(tstr), "%s_halt", parent_->getObjName()); + RISCV_event_create(&eventHalt_, tstr); + RISCV_sprintf(tstr, sizeof(tstr), "%s_delay_ms", parent_->getObjName()); + RISCV_event_create(&eventDelayMs_, tstr); + RISCV_sprintf(tstr, sizeof(tstr), "%s_pwr", parent_->getObjName()); + RISCV_event_create(&eventPowerChanged_, tstr); + + RISCV_register_hap(static_cast(this)); +} + +TcpCommands::~TcpCommands() { + RISCV_event_close(&eventHalt_); + RISCV_event_close(&eventDelayMs_); + RISCV_event_close(&eventPowerChanged_); +} + +void TcpCommands::hapTriggered(IFace *isrc, EHapType type, + const char *descr) { + if (type == HAP_Halt) { + RISCV_event_set(&eventHalt_); + } else if (type == HAP_CpuTurnON || type == HAP_CpuTurnOFF) { + RISCV_event_set(&eventPowerChanged_); + } +} + +void TcpCommands::stepCallback(uint64_t t) { + RISCV_event_set(&eventDelayMs_); +} + +void TcpCommands::updateData(const char *buf, int buflen) { + for (int i = 0; i < buflen; i++) { + rxbuf_[rxcnt_++] = buf[i]; + if (buf[i] == 0) { + processCommand(); + rxcnt_ = 0; + } + } +} + +void TcpCommands::processCommand() { + AttributeType cmd; + cmd.from_config(rxbuf_); + if (!cmd.is_list() || cmd.size() < 3) { + return; + } + + uint64_t idx = cmd[0u].to_uint64(); + resp_.make_list(2); + resp_[0u].make_uint64(idx); + resp_[1].make_string("OK"); + + AttributeType &requestType = cmd[1]; + AttributeType &requestAction = cmd[2]; + AttributeType *resp = &resp_[1]; + + if (requestType.is_equal("Command")) { + /** Redirect command to console directly */ + iexec_->exec(requestAction.to_string(), resp, false); + } else if (requestType.is_equal("Breakpoint")) { + /** Breakpoints action */ + if (requestAction[0u].is_equal("Add")) { + br_add(requestAction[1], resp); + } else if (requestAction[0u].is_equal("Remove")) { + br_rm(requestAction[1], resp); + } else { + resp->make_string("Wrong breakpoint command"); + } + } else if (requestType.is_equal("Control")) { + /** Run Control action */ + if (requestAction[0u].is_equal("GoUntil")) { + go_until(requestAction[1], resp); + } else if (requestAction[0u].is_equal("GoMsec")) { + go_msec(requestAction[1], resp); + } else if (requestAction[0u].is_equal("Step")) { + step(requestAction[1].to_int(), resp); + } else if (requestAction[0u].is_equal("PowerOn")) { + power_on(resp); + RISCV_debug("[%" RV_PRI64 "d] Command Power-On", idx); + } else if (requestAction[0u].is_equal("PowerOff")) { + power_off(resp); + RISCV_debug("[%" RV_PRI64 "d] Command Power-Off", idx); + } else { + resp->make_string("Wrong control command"); + } + } else if (requestType.is_equal("Status")) { + /** Pump status */ + if (requestAction.is_equal("IsON")) { + resp->make_boolean(true); + } else if (requestAction.is_equal("IsHalt")) { + //resp->make_boolean(iriscv_->isHalt()); + } else if (requestAction.is_equal("Steps")) { + resp->make_uint64(iclk_->getStepCounter()); + } else if (requestAction.is_equal("TimeSec")) { + double t1 = iclk_->getStepCounter() / iclk_->getFreqHz(); + resp->make_floating(t1); + } else { + resp->make_string("Wrong status command"); + } + } else if (requestType.is_equal("Symbol")) { + /** Symbols table conversion */ + if (requestAction[0u].is_equal("ToAddr")) { + symb2addr(requestAction[1].to_string(), resp); + } else if (requestAction[0u].is_equal("FromAddr")) { + // todo: + } else { + resp->make_string("Wrong symbol command"); + } + } else if (requestType.is_equal("Attribute")) { + IService *isrv = static_cast( + RISCV_get_service(requestAction[0u].to_string())); + if (isrv) { + AttributeType *iatr = static_cast( + isrv->getAttribute(requestAction[1].to_string())); + if (iatr) { + resp->clone(iatr); + } else { + resp->make_string("Attribute not found"); + } + } else { + resp->make_string("Service not found"); + } + } else { + resp->make_list(2); + (*resp)[0u].make_string("ERROR"); + (*resp)[1].make_string("Wrong command format"); + } + resp_.to_config(); +} + +AttributeType *TcpCommands::response() { + return &resp_; +} + +void TcpCommands::br_add(const AttributeType &symb, AttributeType *res) { + uint64_t addr; + if (symb.is_string()) { + AttributeType t1; + symb2addr(symb.to_string(), &t1); + if (t1.is_nil()) { + res->make_string("br_add: Symbol not found"); + return; + } + addr = t1.to_uint64(); + } else if (symb.is_integer()) { + addr = symb.to_uint64(); + } else { + res->make_string("br_add: Wrong format"); + return; + } + char tstr[256]; + RISCV_sprintf(tstr, sizeof(tstr), "br add 0x%x", addr); + iexec_->exec(tstr, res, false); +} + +void TcpCommands::br_rm(const AttributeType &symb, AttributeType *res) { + uint64_t addr; + if (symb.is_string()) { + AttributeType t1; + symb2addr(symb.to_string(), &t1); + if (t1.is_nil()) { + res->make_string("br_rm: Symbol not found"); + return; + } + addr = t1.to_uint64(); + } else if (symb.is_integer()) { + addr = symb.to_uint64(); + } else { + res->make_string("br_rm: Wrong format"); + return; + } + char tstr[256]; + RISCV_sprintf(tstr, sizeof(tstr), "br rm 0x%x", addr); + iexec_->exec(tstr, res, false); +} + +void TcpCommands::step(int cnt, AttributeType *res) { + char tstr[16]; + RISCV_sprintf(tstr, sizeof(tstr), "c %d", cnt); + + int log_level_old = cpuLogLevel_->to_int(); + cpuLogLevel_->make_int64(4); + + RISCV_event_clear(&eventHalt_); + iexec_->exec(tstr, res, false); + RISCV_event_wait(&eventHalt_); + cpuLogLevel_->make_int64(log_level_old); +} + +void TcpCommands::go_until(const AttributeType &symb, AttributeType *res) { + uint64_t addr; + if (symb.is_string()) { + AttributeType t1; + symb2addr(symb.to_string(), &t1); + if (t1.is_nil()) { + res->make_string("br_rm: Symbol not found"); + return; + } + addr = t1.to_uint64(); + } else if (symb.is_integer()) { + addr = symb.to_uint64(); + } else { + res->make_string("br_rm: Wrong format"); + return; + } + // Add breakpoint + char tstr[256]; + RISCV_sprintf(tstr, sizeof(tstr), "br add 0x%x", addr); + iexec_->exec(tstr, res, false); + + // Set CPU LogLevel=1 to hide all debugging messages + int log_level_old = cpuLogLevel_->to_int(); + cpuLogLevel_->make_int64(1); + + // Run simulation + RISCV_event_clear(&eventHalt_); + RISCV_sprintf(tstr, sizeof(tstr), "c", 0); + iexec_->exec(tstr, res, false); + RISCV_event_wait(&eventHalt_); + cpuLogLevel_->make_int64(log_level_old); + + // Remove breakpoint: + RISCV_sprintf(tstr, sizeof(tstr), "br rm 0x%x", addr); + iexec_->exec(tstr, res, false); +} + +void TcpCommands::symb2addr(const char *symbol, AttributeType *res) { + res->make_nil(); + if (!isrc_) { + return; + } + // Letters capitalization: + char capital[256]; + int i = 0; + while (symbol[i]) { + capital[i] = symbol[i]; + if (symbol[i] >= 'a' && symbol[i] <= 'z') { + capital[i] += ('A' - 'a'); + } + i++; + capital[i] = '\0'; + } + uint64_t addr; + if (isrc_->symbol2Address(capital, &addr) == 0) { + res->make_uint64(addr); + return; + } +} + +void TcpCommands::power_on(AttributeType *res) { +} + +void TcpCommands::power_off(AttributeType *res) { +} + +void TcpCommands::go_msec(const AttributeType &msec, AttributeType *res) { + RISCV_event_clear(&eventDelayMs_); + RISCV_event_clear(&eventHalt_); + + uint64_t step = iclk_->getStepCounter(); + double delta = 0.001 * iclk_->getFreqHz() * msec.to_float(); + if (delta == 0) { + delta = 1; + } + iclk_->registerStepCallback(static_cast(this), + step + static_cast(delta)); + + iexec_->exec("c", res, false); + RISCV_event_wait(&eventDelayMs_); + iexec_->exec("s", res, false); + RISCV_event_wait(&eventHalt_); +} + + +} // namespace debugger
remote/tcpcmd.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: remote/tcpcmd.h =================================================================== --- remote/tcpcmd.h (nonexistent) +++ remote/tcpcmd.h (revision 5) @@ -0,0 +1,85 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief TCP commands parser/processor. + */ + +#ifndef __DEBUGGER_TCPCMD_H__ +#define __DEBUGGER_TCPCMD_H__ + +#include +#include +#include +#include +#include "coreservices/ilink.h" +#include "coreservices/ithread.h" +#include "coreservices/icpugen.h" +#include "coreservices/icpuriscv.h" +#include "coreservices/icmdexec.h" +#include "coreservices/isrccode.h" +#include "coreservices/iclock.h" +#include "coreservices/iwire.h" +#include "coreservices/irawlistener.h" + +namespace debugger { + +class TcpCommands : public IRawListener, + public IHap, + public IClockListener { + public: + explicit TcpCommands(IService *parent); + ~TcpCommands(); + + /** IRawListener interface */ + virtual void updateData(const char *buf, int buflen); + + /** IHap */ + virtual void hapTriggered(IFace *isrc, EHapType type, const char *descr); + + /** IClockListener */ + virtual void stepCallback(uint64_t t); + + /** Common acccess methods */ + AttributeType *response(); + + protected: + IFace *getInterface(const char *name) { + return parent_->getInterface(name); + } + + private: + void processCommand(); + void br_add(const AttributeType &symb, AttributeType *res); + void br_rm(const AttributeType &symb, AttributeType *res); + void go_msec(const AttributeType &symb, AttributeType *res); + void go_until(const AttributeType &symb, AttributeType *res); + void step(int cnt, AttributeType *res); + void symb2addr(const char *symbol, AttributeType *res); + void power_on(AttributeType *res); + void power_off(AttributeType *res); + + private: + char rxbuf_[4096]; + int rxcnt_; + AttributeType cpu_; + AttributeType executor_; + AttributeType source_; + + AttributeType resp_; + + IService *parent_; + ICmdExecutor *iexec_; + ISourceCode *isrc_; + ICpuRiscV *iriscv_; + IClock *iclk_; + AttributeType *cpuLogLevel_; + + event_def eventHalt_; + event_def eventDelayMs_; + event_def eventPowerChanged_; +}; + +} // namespace debugger + +#endif // __DEBUGGER_TCPCMD_H__
remote/tcpcmd.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Index: remote/tcpserver.cpp =================================================================== --- remote/tcpserver.cpp (nonexistent) +++ remote/tcpserver.cpp (revision 5) @@ -0,0 +1,229 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief Remote access to debugger via TCP connection. Server side. + */ + +#include "tcpserver.h" + +namespace debugger { + +/** Class registration in the Core */ +REGISTER_CLASS(TcpServer) + +TcpServer::TcpServer(const char *name) : IService(name) { + registerInterface(static_cast(this)); + registerAttribute("Enable", &isEnable_); + registerAttribute("Timeout", &timeout_); + registerAttribute("BlockingMode", &blockmode_); + registerAttribute("HostIP", &hostIP_); + registerAttribute("HostPort", &hostPort_); +} + +void TcpServer::postinitService() { + createServerSocket(); + + if (listen(hsock_, 1) < 0) { + RISCV_error("listen() failed", 0); + return; + } + + /** By default socket was created with Blocking mode */ + if (!blockmode_.to_bool()) { + setBlockingMode(false); + } + + if (isEnable_.to_bool()) { + if (!run()) { + RISCV_error("Can't create thread.", NULL); + return; + } + } +} + +void TcpServer::busyLoop() { + socket_def client_sock; + int err; + + fd_set readSet; + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 400000; // 400 ms + + int idx = 0; + char tname[64]; + + IClass *icls; + IService *isrv; + while (isEnabled()) { + FD_ZERO(&readSet); + FD_SET(hsock_, &readSet); + err = select(hsock_ + 1, &readSet, NULL, NULL, &timeout); + if (err > 0) { + client_sock = accept(hsock_, 0, 0); + setRcvTimeout(client_sock, timeout_.to_int()); + RISCV_sprintf(tname, sizeof(tname), "client%d", idx++); + + icls = static_cast(RISCV_get_class("TcpClientClass")); + isrv = icls->createService(tname); + AttributeType lst, item; + lst.make_list(0); + item.make_list(2); + item[0u].make_string("LogLevel"); + item[1].make_int64(4); + lst.add_to_list(&item); + item[0u].make_string("Enable"); + item[1].make_boolean(true); + lst.add_to_list(&item); + + isrv->initService(&lst); + IThread *ithrd = + static_cast(isrv->getInterface(IFACE_THREAD)); + ithrd->setExtArgument(&client_sock); + isrv->postinitService(); + RISCV_info("TCP %s %p started", isrv->getObjName(), client_sock); + } else if (err == 0) { + // timeout + } else { + RISCV_info("TCP server thread accept() failed", 0); + loopEnable_.state = false; + } + } + closeServerSocket(); +} + +int TcpServer::createServerSocket() { + char hostName[256]; + if (gethostname(hostName, sizeof(hostName)) < 0) { + return -1; + } + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + /** + * Check availability of IPv4 address assigned via attribute 'hostIP'. + * If it woudn't be found use the last avaialble IP address. + */ + int retval; + struct addrinfo *result = NULL; + struct addrinfo *ptr = NULL; + retval = getaddrinfo(hostName, "0", &hints, &result); + if (retval != 0) { + return -1; + } + + if (hostIP_.size() == 0 || hostIP_.is_equal("127.0.0.1")) { + memset(&sockaddr_ipv4_, 0, sizeof(struct sockaddr_in)); + sockaddr_ipv4_.sin_family = AF_INET; + sockaddr_ipv4_.sin_addr.s_addr = inet_addr("127.0.0.1"); + } else { + for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { + // Find only IPV4 address, ignore others. + if (ptr->ai_family != AF_INET) { + continue; + } + sockaddr_ipv4_ = *((struct sockaddr_in *)ptr->ai_addr); + + if (hostIP_.is_equal(inet_ntoa(sockaddr_ipv4_.sin_addr))) { + break; + } + } + } + sockaddr_ipv4_.sin_port = htons(static_cast(hostPort_.to_int())); + RISCV_info("Selected Host IPv4 %s:%d", + inet_ntoa(sockaddr_ipv4_.sin_addr), + hostPort_.to_uint32()); + + hsock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (hsock_ < 0) { + RISCV_error("%s", "Error: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)"); + return -1; + } + + int res = bind(hsock_, + reinterpret_cast(&sockaddr_ipv4_), + sizeof(sockaddr_ipv4_)); + if (res != 0) { + RISCV_error("Error: bind(hsock_, \"%s\", ...)", hostIP_.to_string()); + return -1; + } + + addr_size_t addr_sz = sizeof(sockaddr_ipv4_); + res = getsockname(hsock_, + reinterpret_cast(&sockaddr_ipv4_), + &addr_sz); + + RISCV_info("IPv4 address %s:%d . . . opened", + inet_ntoa(sockaddr_ipv4_.sin_addr), + ntohs(sockaddr_ipv4_.sin_port)); + + return 0; +} + +void TcpServer::setRcvTimeout(socket_def skt, int timeout_ms) { + if (!timeout_ms) { + return; + } + struct timeval tv; +#if defined(_WIN32) || defined(__CYGWIN__) + /** On windows timeout of the setsockopt() function is the DWORD + * size variable in msec, so we use only the first field in timeval + * struct and directly assgign argument. + */ + tv.tv_sec = timeout_ms; + tv.tv_usec = 0; +#else + tv.tv_usec = (timeout_ms % 1000) * 1000; + tv.tv_sec = timeout_ms / 1000; +#endif + setsockopt(skt, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&tv), sizeof(struct timeval)); +} + +bool TcpServer::setBlockingMode(bool mode) { + int ret; +#if defined(_WIN32) || defined(__CYGWIN__) + // 0 = disable non-blocking mode + // 1 = enable non-blocking mode + u_long arg = mode ? 0 : 1; + ret = ioctlsocket(hsock_, FIONBIO, &arg); + if (ret == SOCKET_ERROR) { + RISCV_error("Set non-blocking socket failed", 0); + } +#else + int flags = fcntl(hsock_, F_GETFL, 0); + if (flags < 0) { + return false; + } + flags = mode ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + ret = fcntl(hsock_, F_SETFL, flags); +#endif + if (ret == 0) { + // success + blockmode_.make_boolean(mode); + return true; + } + return false; +} + +void TcpServer::closeServerSocket() { + if (hsock_ < 0) { + return; + } + +#if defined(_WIN32) || defined(__CYGWIN__) + closesocket(hsock_); +#else + shutdown(hsock_, SHUT_RDWR); + close(hsock_); +#endif + hsock_ = -1; +} + + +} // namespace debugger
remote/tcpserver.cpp Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: remote/tcpserver.h =================================================================== --- remote/tcpserver.h (nonexistent) +++ remote/tcpserver.h (revision 5) @@ -0,0 +1,52 @@ +/** + * @file + * @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved. + * @author Sergey Khabarov - sergeykhbr@gmail.com + * @brief Remote access to debugger via TCP connection. Server side. + */ + +#ifndef __DEBUGGER_TCPSERVER_H__ +#define __DEBUGGER_TCPSERVER_H__ + +#include +#include +#include "coreservices/ithread.h" +#include "tcpclient.h" + +namespace debugger { + +class TcpServer : public IService, + public IThread { + public: + explicit TcpServer(const char *name); + + /** IService interface */ + virtual void postinitService(); + + protected: + /** IThread interface */ + virtual void busyLoop(); + + protected: + int createServerSocket(); + void closeServerSocket(); + void setRcvTimeout(socket_def skt, int timeout_ms); + bool setBlockingMode(bool mode); + + private: + AttributeType isEnable_; + AttributeType timeout_; + AttributeType blockmode_; + AttributeType hostIP_; + AttributeType hostPort_; + + struct sockaddr_in sockaddr_ipv4_; + socket_def hsock_; + char rcvbuf[4096]; +}; + +DECLARE_CLASS(TcpServer) + +} // namespace debugger + +#endif // __DEBUGGER_TCPSERVER_H__
remote/tcpserver.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property

powered by: WebSVN 2.1.0

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