-
Notifications
You must be signed in to change notification settings - Fork 44
/
jtag_vpi.c
360 lines (284 loc) · 8.26 KB
/
jtag_vpi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/*
* TCP/IP controlled VPI JTAG Interface.
* Based on Julius Baxter's work on jp_vpi.c
*
* SPDX-FileCopyrightText: 2020 Jan Matyas
* SPDX-FileCopyrightText: 2019 Olof Kindgren
* SPDX-FileCopyrightText: 2012 Franck Jullien <franck.jullien@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arpa/inet.h>
#include <vpi_user.h>
#include "jtag_common.h"
static void terminate_simulation(void)
{
vpi_control(vpiFinish, 1);
}
void vpi_check_for_command(char *userdata)
{
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
struct jtag_cmd cmd;
unsigned loaded_words = 0;
int ret;
(void)userdata;
// See if there is an incoming JTAG command
ret = check_for_command(&cmd);
if (ret == JTAG_SERVER_TRY_LATER) {
// No command from OpenOCD at this time
return;
}
else if (ret != JTAG_SERVER_SUCCESS) {
if (ret == JTAG_SERVER_CLIENT_DISCONNECTED) {
// OpenOCD disconnected
vpi_printf("Ending simulation. Reason: jtag_vpi client disconnection.\n");
}
else {
// A communication error ocurred, cannot continue
vpi_printf("Ending simulation. Reason: Error communicating with OpenOCD.\n");
}
terminate_simulation();
return;
}
// New command from OpenOCD arrived. Push it to the RTL simulation:
/************* vpi.cmd to VPI ******************************/
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
// get a handle on the variable passed to the function
argh = vpi_scan(args_iter);
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
argval.value.integer = (uint32_t)cmd.cmd;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
/************* vpi.length to VPI ******************************/
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
argval.value.integer = (uint32_t)cmd.length;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
/************* vpi.nb_bits to VPI ******************************/
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
argval.value.integer = (uint32_t)cmd.nb_bits;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
/*****************vpi.buffer_out to VPI ********/
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
vpiHandle array_word;
// Loop to load the words
while (loaded_words < cmd.length) {
// now get a handle on the current word we want in the array that was passed to us
array_word = vpi_handle_by_index(argh, loaded_words);
if (array_word != NULL) {
argval.value.integer = (uint32_t)cmd.buffer_out[loaded_words];
// And vpi_put_value() it back into the sim
vpi_put_value(array_word, &argval, NULL, vpiNoDelay);
} else
return;
loaded_words++;
}
/*******************************************/
// Cleanup and return
vpi_free_object(args_iter);
}
void vpi_send_result_to_server(char *userdata)
{
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
struct jtag_cmd cmd;
int32_t length;
int sent_words;
vpiHandle array_word;
(void)userdata;
// Now setup the handles to verilog objects and check things
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
// get a handle on the length variable
argh = vpi_scan(args_iter);
argval.format = vpiIntVal;
// get the value for the length object
vpi_get_value(argh, &argval);
// now set length
length = argval.value.integer;
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
// check we got passed a memory (array of regs)
if (!((vpi_get(vpiType, argh) == vpiMemory) || (vpi_get(vpiType, argh) == vpiRegArray))) {
vpi_printf("jtag_vpi: ERROR: did not pass a memory/regArray to get_command_block_data\n");
vpi_printf("jtag_vpi: ERROR: was passed type %d\n", (int)vpi_get(vpiType, argh));
return;
}
// check the memory we're writing into is big enough
if (vpi_get(vpiSize, argh) < length ) {
vpi_printf("jtag_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n",
vpi_get(vpiSize, argh), length);
return;
}
// Loop to load the words
sent_words = 0;
while (sent_words < length) {
// Get a handle on the current word we want in the array that was passed to us
array_word = vpi_handle_by_index(argh, sent_words);
if (array_word != NULL) {
vpi_get_value(array_word, &argval);
cmd.buffer_in[sent_words] = (uint32_t) argval.value.integer;
} else
return;
sent_words++;
}
if (send_result_to_server(&cmd) != JTAG_SERVER_SUCCESS) {
vpi_printf("Ending simulation. Reason: Cannot send data back to OpenOCD.\n");
terminate_simulation();
return;
}
// Cleanup and return
vpi_free_object(args_iter);
}
void print_func(char *msg)
{
vpi_printf("%s", msg);
}
void setup_jtag_server_print(void)
{
// Provide a callback to jtag_common.c so that messages can be printed.
jtag_server_set_print_func(print_func);
}
void register_check_for_command(void)
{
s_vpi_systf_data data = {
vpiSysTask,
0,
"$check_for_command",
(void *)vpi_check_for_command,
0,
0,
0
};
vpi_register_systf(&data);
}
void register_send_result_to_server(void)
{
s_vpi_systf_data data = {
vpiSysTask,
0,
"$send_result_to_server",
(void *)vpi_send_result_to_server,
0,
0,
0
};
vpi_register_systf(&data);
}
void sim_reset_callback(void)
{
// nothing to do!
}
void setup_reset_callbacks(void)
{
// here we setup and install callbacks for
// the setup and management of connections to
// the simulator upon simulation start and
// reset
static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0};
static s_vpi_value value_s = {.format = vpiBinStrVal};
static s_cb_data cb_data_s = {
cbEndOfReset, // or start of simulation - initing socket fds etc
(void *)sim_reset_callback,
NULL,
&time_s,
&value_s,
0,
NULL
};
cb_data_s.obj = NULL; /* trigger object */
cb_data_s.user_data = NULL;
// actual call to register the callback
vpi_register_cb(&cb_data_s);
}
void sim_endofcompile_callback(void)
{
}
void setup_endofcompile_callbacks(void)
{
// here we setup and install callbacks for
// simulation finish
static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0};
static s_vpi_value value_s = {.format = vpiBinStrVal};
static s_cb_data cb_data_s = {
cbEndOfCompile, // end of compile
(void *)sim_endofcompile_callback,
NULL,
&time_s,
&value_s,
0,
NULL
};
cb_data_s.obj = NULL; /* trigger object */
cb_data_s.user_data = NULL;
// actual call to register the callback
vpi_register_cb(&cb_data_s);
}
void sim_finish_callback(void)
{
jtag_server_finish();
}
void setup_finish_callbacks(void)
{
// here we setup and install callbacks for
// simulation finish
static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0};
static s_vpi_value value_s = {.format = vpiBinStrVal};
static s_cb_data cb_data_s = {
cbEndOfSimulation, // end of simulation
(void *)sim_finish_callback,
NULL,
&time_s,
&value_s,
0,
NULL
};
cb_data_s.obj = NULL; /* trigger object */
cb_data_s.user_data = NULL;
// actual call to register the callback
vpi_register_cb(&cb_data_s);
}
#ifndef VCS_VPI
// Register the new system task here
void (*vlog_startup_routines[])(void) = {
#ifdef CDS_VPI
// this installs a callback on simulator reset - something which
// icarus does not do, so we only do it for cadence currently
setup_reset_callbacks,
#endif
setup_endofcompile_callbacks,
setup_finish_callbacks,
register_check_for_command,
register_send_result_to_server,
setup_jtag_server_print,
0 // last entry must be 0
};
// Entry point for testing development of the vpi functions
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
return 0;
}
#endif