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 |
|
|
* Packet format:
|
17 |
|
|
* Write command:
|
18 |
|
|
* Send [11.Length-1].Addr[63:0].Data[31:0]*(x Length)
|
19 |
|
|
* Read command:
|
20 |
|
|
* Send [10.Length-1].Addr[63:0]
|
21 |
|
|
* Receive Data[31:0]*(x Length)
|
22 |
|
|
*/
|
23 |
|
|
|
24 |
|
|
#include "api_core.h"
|
25 |
|
|
#include "uartmst.h"
|
26 |
|
|
#include "coreservices/isocinfo.h"
|
27 |
|
|
|
28 |
|
|
namespace debugger {
|
29 |
|
|
|
30 |
|
|
static const uint32_t UART_STATUS_TX_FULL = 0x00000001;
|
31 |
|
|
static const uint32_t UART_STATUS_TX_EMPTY = 0x00000002;
|
32 |
|
|
static const uint32_t UART_STATUS_RX_FULL = 0x00000010;
|
33 |
|
|
static const uint32_t UART_STATUS_RX_EMPTY = 0x00000020;
|
34 |
|
|
static const uint32_t UART_STATUS_ERR_PARITY = 0x00000100;
|
35 |
|
|
static const uint32_t UART_STATUS_ERR_STOPBIT = 0x00000200;
|
36 |
|
|
static const uint32_t UART_CONTROL_RX_IRQ_ENA = 0x00002000;
|
37 |
|
|
static const uint32_t UART_CONTROL_TX_IRQ_ENA = 0x00004000;
|
38 |
|
|
static const uint32_t UART_CONTROL_PARITY_ENA = 0x00008000;
|
39 |
|
|
|
40 |
|
|
|
41 |
|
|
UartMst::UartMst(const char *name) : IService(name) {
|
42 |
|
|
registerInterface(static_cast<IThread *>(this));
|
43 |
|
|
registerInterface(static_cast<IAxi4NbResponse *>(this));
|
44 |
|
|
registerInterface(static_cast<ISerial *>(this));
|
45 |
|
|
registerAttribute("Bus", &bus_);
|
46 |
|
|
|
47 |
|
|
listeners_.make_list(0);
|
48 |
|
|
bus_.make_string("");
|
49 |
|
|
|
50 |
|
|
RISCV_event_create(&event_tap_, "UartMst_event_tap");
|
51 |
|
|
RISCV_event_create(&event_request_, "UartMst_event_request");
|
52 |
|
|
RISCV_event_create(&event_accept_, "UartMst_event_accept");
|
53 |
|
|
RISCV_mutex_init(&mutexListeners_);
|
54 |
|
|
|
55 |
|
|
memset(®s_, 0, sizeof(regs_));
|
56 |
|
|
regs_.status = UART_STATUS_TX_EMPTY | UART_STATUS_RX_EMPTY;
|
57 |
|
|
|
58 |
|
|
txbuf_sz_ = 0;
|
59 |
|
|
baudrate_detect_ = false;
|
60 |
|
|
}
|
61 |
|
|
|
62 |
|
|
UartMst::~UartMst() {
|
63 |
|
|
RISCV_event_close(&event_tap_);
|
64 |
|
|
RISCV_event_close(&event_request_);
|
65 |
|
|
RISCV_event_close(&event_accept_);
|
66 |
|
|
RISCV_mutex_destroy(&mutexListeners_);
|
67 |
|
|
}
|
68 |
|
|
|
69 |
|
|
void UartMst::postinitService() {
|
70 |
|
|
ibus_ = static_cast<IMemoryOperation *>(
|
71 |
|
|
RISCV_get_service_iface(bus_.to_string(), IFACE_MEMORY_OPERATION));
|
72 |
|
|
if (!ibus_) {
|
73 |
|
|
RISCV_error("Can't find IBus interface %s", bus_.to_string());
|
74 |
|
|
}
|
75 |
|
|
run();
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
void UartMst::busyLoop() {
|
79 |
|
|
UartMstPacketType packet;
|
80 |
|
|
RISCV_info("UartMst thread was started", NULL);
|
81 |
|
|
trans_.source_idx = CFG_NASTI_MASTER_MSTUART; // Hardcoded in VHDL value
|
82 |
|
|
|
83 |
|
|
int burst_sz;
|
84 |
|
|
while (isEnabled()) {
|
85 |
|
|
if (RISCV_event_wait_ms(&event_request_, 50) != 0) {
|
86 |
|
|
continue;
|
87 |
|
|
}
|
88 |
|
|
RISCV_event_clear(&event_request_);
|
89 |
|
|
memcpy(&packet, txbuf_.buf, sizeof(packet));
|
90 |
|
|
RISCV_event_set(&event_accept_);
|
91 |
|
|
txbuf_sz_ = 0;
|
92 |
|
|
|
93 |
|
|
if (!baudrate_detect_) {
|
94 |
|
|
// Symbol 0x55 runs baudrate detector
|
95 |
|
|
if (packet.cmd == 0x55) {
|
96 |
|
|
baudrate_detect_ = true;
|
97 |
|
|
}
|
98 |
|
|
continue;
|
99 |
|
|
}
|
100 |
|
|
|
101 |
|
|
if ((packet.cmd & 0x80) == 0) {
|
102 |
|
|
RISCV_error("Wrong request format", NULL);
|
103 |
|
|
continue;
|
104 |
|
|
}
|
105 |
|
|
|
106 |
|
|
trans_.addr = packet.addr.val & 0xFFFFFFFF;
|
107 |
|
|
trans_.xsize = 4;
|
108 |
|
|
if ((packet.cmd & 0x40) == 0) {
|
109 |
|
|
trans_.action = MemAction_Read;
|
110 |
|
|
} else {
|
111 |
|
|
trans_.action = MemAction_Write;
|
112 |
|
|
trans_.wstrb = (1 << trans_.xsize) - 1;
|
113 |
|
|
}
|
114 |
|
|
|
115 |
|
|
burst_sz = (packet.cmd & 0x3F) + 1;
|
116 |
|
|
for (int i = 0; i < burst_sz; i++) {
|
117 |
|
|
if (trans_.action == MemAction_Write) {
|
118 |
|
|
trans_.wpayload.b32[0] = packet.data[0].buf32[i];
|
119 |
|
|
}
|
120 |
|
|
RISCV_event_clear(&event_tap_);
|
121 |
|
|
ibus_->nb_transport(&trans_, this);
|
122 |
|
|
if (RISCV_event_wait_ms(&event_tap_, 500) != 0) {
|
123 |
|
|
RISCV_error("CPU queue callback timeout", NULL);
|
124 |
|
|
} else if (trans_.action == MemAction_Read) {
|
125 |
|
|
RISCV_mutex_lock(&mutexListeners_);
|
126 |
|
|
for (unsigned n = 0; n < listeners_.size(); n++) {
|
127 |
|
|
IRawListener *lstn = static_cast<IRawListener *>(
|
128 |
|
|
listeners_[n].to_iface());
|
129 |
|
|
lstn->updateData(
|
130 |
|
|
reinterpret_cast<char *>(trans_.rpayload.b8),
|
131 |
|
|
trans_.xsize);
|
132 |
|
|
}
|
133 |
|
|
RISCV_mutex_unlock(&mutexListeners_);
|
134 |
|
|
}
|
135 |
|
|
trans_.addr += 4;
|
136 |
|
|
}
|
137 |
|
|
}
|
138 |
|
|
}
|
139 |
|
|
|
140 |
|
|
int UartMst::writeData(const char *buf, int sz) {
|
141 |
|
|
if (sz > static_cast<int>(sizeof(UartMstPacketType))) {
|
142 |
|
|
RISCV_error("Request will be truncated", NULL);
|
143 |
|
|
sz = sizeof(UartMstPacketType);
|
144 |
|
|
}
|
145 |
|
|
memcpy(txbuf_.buf, buf, sz);
|
146 |
|
|
txbuf_sz_ = sz;
|
147 |
|
|
RISCV_event_clear(&event_accept_);
|
148 |
|
|
RISCV_event_set(&event_request_);
|
149 |
|
|
RISCV_event_wait_ms(&event_accept_, 500);
|
150 |
|
|
return sz;
|
151 |
|
|
}
|
152 |
|
|
|
153 |
|
|
void UartMst::registerRawListener(IFace *listener) {
|
154 |
|
|
AttributeType lstn(listener);
|
155 |
|
|
RISCV_mutex_lock(&mutexListeners_);
|
156 |
|
|
listeners_.add_to_list(&lstn);
|
157 |
|
|
RISCV_mutex_unlock(&mutexListeners_);
|
158 |
|
|
}
|
159 |
|
|
|
160 |
|
|
void UartMst::unregisterRawListener(IFace *listener) {
|
161 |
|
|
RISCV_mutex_lock(&mutexListeners_);
|
162 |
|
|
for (unsigned i = 0; i < listeners_.size(); i++) {
|
163 |
|
|
IFace *iface = listeners_[i].to_iface();
|
164 |
|
|
if (iface == listener) {
|
165 |
|
|
listeners_.remove_from_list(i);
|
166 |
|
|
break;
|
167 |
|
|
}
|
168 |
|
|
}
|
169 |
|
|
RISCV_mutex_unlock(&mutexListeners_);
|
170 |
|
|
}
|
171 |
|
|
|
172 |
|
|
void UartMst::getListOfPorts(AttributeType *list) {
|
173 |
|
|
list->make_list(0);
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
int UartMst::openPort(const char *port, AttributeType settings) {
|
177 |
|
|
return 0;
|
178 |
|
|
}
|
179 |
|
|
|
180 |
|
|
void UartMst::closePort() {
|
181 |
|
|
}
|
182 |
|
|
|
183 |
|
|
void UartMst::nb_response(Axi4TransactionType *trans) {
|
184 |
|
|
RISCV_event_set(&event_tap_);
|
185 |
|
|
}
|
186 |
|
|
|
187 |
|
|
} // namespace debugger
|
188 |
|
|
|