origen_sim 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/version.rb +1 -1
- data/ext/README.md +2 -0
- data/ext/bridge.c +790 -0
- data/ext/bridge.h +9 -0
- data/ext/client.c +98 -0
- data/ext/client.h +11 -0
- data/ext/common.h +22 -0
- data/ext/origen.c +121 -0
- data/ext/origen.h +9 -0
- data/ext/vpi_user.h +924 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d43f5b6b5fbd5690d6102a112092e4faab826395
|
4
|
+
data.tar.gz: 556101429de33f89de0898a205b5484dc8112af1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: baaf314cedd9d9af37b8ee73da872f35381651ad906fbd2607ac55650a04169e8eb04ce61c09bb64621425538e5e0c6dc760d302d5c8214a837d21b4cef6d70a
|
7
|
+
data.tar.gz: 740dcff5b5b89ecf3e41e7e872b6533757c7ee7834bb5cbd73454add475159ee70e2bc8e5962aaef9839b371ade03fc7fab46ca7301e46b846e0b0ef6f33c5a2
|
data/config/version.rb
CHANGED
data/ext/README.md
ADDED
data/ext/bridge.c
ADDED
@@ -0,0 +1,790 @@
|
|
1
|
+
///
|
2
|
+
/// This implements the bridge between Origen and the simulation, it implements a
|
3
|
+
/// simple string-based message protocol for communicating between the two domains
|
4
|
+
///
|
5
|
+
#include "bridge.h"
|
6
|
+
#include "client.h"
|
7
|
+
#include <stdint.h>
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdbool.h>
|
11
|
+
#include <string.h>
|
12
|
+
|
13
|
+
#define MAX_NUMBER_PINS 2000
|
14
|
+
#define MAX_WAVE_EVENTS 10
|
15
|
+
|
16
|
+
typedef struct Pin {
|
17
|
+
vpiHandle data; // A handle to the driver data register
|
18
|
+
vpiHandle drive; // A handle to the driver drive enable register
|
19
|
+
vpiHandle force_data; // A handle to the driver force_data register
|
20
|
+
vpiHandle compare; // A handle to the driver compare enable register
|
21
|
+
vpiHandle capture; // A handle to the driver capture enable register
|
22
|
+
int drive_wave; // Index of the drive wave to be used for this pin
|
23
|
+
int compare_wave; // Index of the compare wave to be used for this pin
|
24
|
+
int drive_wave_pos; // Position of the pin in the drive_wave's active pin array
|
25
|
+
int compare_wave_pos; // Position of the pin in the compare_wave's active pin array
|
26
|
+
int index; // The pin's index in the pins array
|
27
|
+
int previous_state; // Used to keep track of whether the pin was previously driving or comparing
|
28
|
+
bool capture_en; // Used to indicated when compare data should be captured instead of compared
|
29
|
+
} Pin;
|
30
|
+
|
31
|
+
typedef struct Event {
|
32
|
+
int time;
|
33
|
+
char data;
|
34
|
+
} Event;
|
35
|
+
|
36
|
+
typedef struct Wave {
|
37
|
+
Event events[MAX_WAVE_EVENTS];
|
38
|
+
Pin *active_pins[MAX_NUMBER_PINS];
|
39
|
+
int active_pin_count;
|
40
|
+
} Wave;
|
41
|
+
|
42
|
+
static int period_in_ns;
|
43
|
+
static long repeat = 0;
|
44
|
+
static Pin pins[MAX_NUMBER_PINS];
|
45
|
+
static int number_of_pins = 0;
|
46
|
+
// Allocate space for a unique wave for each pin, in reality it will be much less
|
47
|
+
static Wave drive_waves[MAX_NUMBER_PINS];
|
48
|
+
static int number_of_drive_waves = 0;
|
49
|
+
static Wave compare_waves[MAX_NUMBER_PINS];
|
50
|
+
static int number_of_compare_waves = 0;
|
51
|
+
static int runtime_errors = 0;
|
52
|
+
static int log_messages = 0;
|
53
|
+
|
54
|
+
static void bridge_set_period(char*);
|
55
|
+
static void bridge_define_pin(char*, char*, char*, char*);
|
56
|
+
static void bridge_define_wave(char*, char*, char*);
|
57
|
+
static void bridge_cycle(void);
|
58
|
+
static void bridge_drive_pin(char*, char*);
|
59
|
+
static void bridge_compare_pin(char*, char*);
|
60
|
+
static void bridge_capture_pin(char*);
|
61
|
+
static void bridge_stop_capture_pin(char*);
|
62
|
+
static void bridge_dont_care_pin(char*);
|
63
|
+
static void bridge_register_wave_events(void);
|
64
|
+
static void bridge_register_wave_event(int, int, int, int);
|
65
|
+
static void bridge_enable_drive_wave(Pin*);
|
66
|
+
static void bridge_disable_drive_wave(Pin*);
|
67
|
+
static void bridge_enable_compare_wave(Pin*);
|
68
|
+
static void bridge_disable_compare_wave(Pin*);
|
69
|
+
static void bridge_clear_waves_and_pins(void);
|
70
|
+
static bool bridge_is_drive_whole_cycle(Pin*);
|
71
|
+
static void end_simulation(void);
|
72
|
+
|
73
|
+
static void bridge_define_pin(char * name, char * pin_ix, char * drive_wave_ix, char * compare_wave_ix) {
|
74
|
+
int index = atoi(pin_ix);
|
75
|
+
Pin *pin = &pins[index];
|
76
|
+
number_of_pins += 1;
|
77
|
+
|
78
|
+
(*pin).index = index;
|
79
|
+
(*pin).drive_wave = atoi(drive_wave_ix);
|
80
|
+
(*pin).compare_wave = atoi(compare_wave_ix);
|
81
|
+
(*pin).previous_state = 0;
|
82
|
+
(*pin).capture_en = false;
|
83
|
+
|
84
|
+
char * driver = (char *) malloc(strlen(name) + 16);
|
85
|
+
strcpy(driver, "origen.pins.");
|
86
|
+
strcat(driver, name);
|
87
|
+
|
88
|
+
char * data = (char *) malloc(strlen(driver) + 16);
|
89
|
+
strcpy(data, driver);
|
90
|
+
strcat(data, ".data");
|
91
|
+
(*pin).data = vpi_handle_by_name(data, NULL);
|
92
|
+
free(data);
|
93
|
+
|
94
|
+
char * drive = (char *) malloc(strlen(driver) + 16);
|
95
|
+
strcpy(drive, driver);
|
96
|
+
strcat(drive, ".drive");
|
97
|
+
(*pin).drive = vpi_handle_by_name(drive, NULL);
|
98
|
+
free(drive);
|
99
|
+
|
100
|
+
char * force = (char *) malloc(strlen(driver) + 16);
|
101
|
+
strcpy(force, driver);
|
102
|
+
strcat(force, ".force_data");
|
103
|
+
(*pin).force_data = vpi_handle_by_name(force, NULL);
|
104
|
+
free(force);
|
105
|
+
|
106
|
+
char * compare = (char *) malloc(strlen(driver) + 16);
|
107
|
+
strcpy(compare, driver);
|
108
|
+
strcat(compare, ".compare");
|
109
|
+
(*pin).compare = vpi_handle_by_name(compare, NULL);
|
110
|
+
free(compare);
|
111
|
+
|
112
|
+
char * capture = (char *) malloc(strlen(driver) + 16);
|
113
|
+
strcpy(capture, driver);
|
114
|
+
strcat(capture, ".capture");
|
115
|
+
(*pin).capture = vpi_handle_by_name(capture, NULL);
|
116
|
+
free(capture);
|
117
|
+
|
118
|
+
free(driver);
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
static void bridge_define_wave(char * index, char * compare, char * events) {
|
123
|
+
int ix = atoi(index);
|
124
|
+
Wave * wave;
|
125
|
+
|
126
|
+
if (compare[0] == '0') {
|
127
|
+
wave = &drive_waves[ix];
|
128
|
+
number_of_drive_waves += 1;
|
129
|
+
} else {
|
130
|
+
wave = &compare_waves[ix];
|
131
|
+
number_of_compare_waves += 1;
|
132
|
+
}
|
133
|
+
|
134
|
+
char * token;
|
135
|
+
// strtok needs a writable copy of events
|
136
|
+
char * myevents = (char *) malloc(strlen(events) + 1);
|
137
|
+
strcpy(myevents, events);
|
138
|
+
|
139
|
+
int i = 0;
|
140
|
+
token = strtok(myevents, "_");
|
141
|
+
|
142
|
+
while (token != NULL) {
|
143
|
+
(*wave).events[i].time = (int)strtol(token, NULL, 10);
|
144
|
+
token = strtok(NULL, "_");
|
145
|
+
(*wave).events[i].data = token[0];
|
146
|
+
token = strtok(NULL, "_");
|
147
|
+
i++;
|
148
|
+
}
|
149
|
+
(*wave).events[i].data = 'T'; // Indicate that there are no more events
|
150
|
+
free(myevents);
|
151
|
+
(*wave).active_pin_count = 0;
|
152
|
+
}
|
153
|
+
|
154
|
+
|
155
|
+
static void bridge_register_wave_events() {
|
156
|
+
for (int i = 0; i < number_of_drive_waves; i++) {
|
157
|
+
|
158
|
+
if (drive_waves[i].active_pin_count) {
|
159
|
+
int x = 0;
|
160
|
+
|
161
|
+
while (drive_waves[i].events[x].data != 'T' && x < MAX_WAVE_EVENTS) {
|
162
|
+
int time;
|
163
|
+
|
164
|
+
time = drive_waves[i].events[x].time;
|
165
|
+
|
166
|
+
// TODO: May save some time by calling directly at time 0
|
167
|
+
//if (time == 0) {
|
168
|
+
//} else {
|
169
|
+
bridge_register_wave_event(i, x, 0, time);
|
170
|
+
//}
|
171
|
+
x++;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
for (int i = 0; i < number_of_compare_waves; i++) {
|
177
|
+
|
178
|
+
if (compare_waves[i].active_pin_count) {
|
179
|
+
int x = 0;
|
180
|
+
|
181
|
+
while (compare_waves[i].events[x].data != 'T' && x < MAX_WAVE_EVENTS) {
|
182
|
+
int time;
|
183
|
+
|
184
|
+
time = compare_waves[i].events[x].time;
|
185
|
+
|
186
|
+
// TODO: May save some time by calling directly at time 0
|
187
|
+
//if (time == 0) {
|
188
|
+
//} else {
|
189
|
+
bridge_register_wave_event(i, x, 1, time);
|
190
|
+
//}
|
191
|
+
x++;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
/// Enables the drive condition of the given pin.
|
199
|
+
/// This is done by adding the pin to the wave's active pin list, if the wave has
|
200
|
+
/// at least one pin in its list, the necessary callbacks will get triggered on every
|
201
|
+
/// cycle to implement the required waveform.
|
202
|
+
static void bridge_enable_drive_wave(Pin * pin) {
|
203
|
+
Wave *wave = &drive_waves[(*pin).drive_wave];
|
204
|
+
|
205
|
+
(*wave).active_pins[(*wave).active_pin_count] = pin;
|
206
|
+
(*pin).drive_wave_pos = (*wave).active_pin_count;
|
207
|
+
(*wave).active_pin_count += 1;
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
static void bridge_disable_drive_wave(Pin * pin) {
|
212
|
+
Wave *wave = &compare_waves[(*pin).drive_wave];
|
213
|
+
|
214
|
+
if ((*wave).active_pin_count == 0) {
|
215
|
+
vpi_printf("Wanted to disable drive on pin %i, but its drive wave has no active pins!\n", (*pin).index);
|
216
|
+
end_simulation();
|
217
|
+
}
|
218
|
+
|
219
|
+
// If pin is last, we can clear it by just decrementing the active pin counter
|
220
|
+
if ((*pin).drive_wave_pos != (*wave).active_pin_count - 1) {
|
221
|
+
// Otherwise we can remove it by overwriting it with the current last pin in the
|
222
|
+
// array, since the order is not important
|
223
|
+
(*wave).active_pins[(*pin).drive_wave_pos] = (*wave).active_pins[(*wave).active_pin_count - 1];
|
224
|
+
// Need to let the moved pin know its new position
|
225
|
+
(*(*wave).active_pins[(*pin).drive_wave_pos]).drive_wave_pos = (*pin).drive_wave_pos;
|
226
|
+
}
|
227
|
+
|
228
|
+
(*wave).active_pin_count -= 1;
|
229
|
+
}
|
230
|
+
|
231
|
+
static void bridge_enable_compare_wave(Pin * pin) {
|
232
|
+
Wave *wave = &compare_waves[(*pin).compare_wave];
|
233
|
+
|
234
|
+
(*wave).active_pins[(*wave).active_pin_count] = pin;
|
235
|
+
(*pin).compare_wave_pos = (*wave).active_pin_count;
|
236
|
+
(*wave).active_pin_count += 1;
|
237
|
+
}
|
238
|
+
|
239
|
+
static void bridge_disable_compare_wave(Pin * pin) {
|
240
|
+
Wave *wave = &compare_waves[(*pin).compare_wave];
|
241
|
+
|
242
|
+
// If pin is last, we can clear it by just decrementing the active pin counter
|
243
|
+
if ((*pin).compare_wave_pos != (*wave).active_pin_count - 1) {
|
244
|
+
// Otherwise we can remove it by overwriting it with the current last pin in the
|
245
|
+
// array, since the order is not important
|
246
|
+
(*wave).active_pins[(*pin).compare_wave_pos] = (*wave).active_pins[(*wave).active_pin_count - 1];
|
247
|
+
// Need to let the moved pin know its new position
|
248
|
+
(*(*wave).active_pins[(*pin).compare_wave_pos]).compare_wave_pos = (*pin).compare_wave_pos;
|
249
|
+
}
|
250
|
+
|
251
|
+
(*wave).active_pin_count -= 1;
|
252
|
+
}
|
253
|
+
|
254
|
+
|
255
|
+
static void bridge_clear_waves_and_pins() {
|
256
|
+
number_of_pins = 0;
|
257
|
+
number_of_drive_waves = 0;
|
258
|
+
number_of_compare_waves = 0;
|
259
|
+
}
|
260
|
+
|
261
|
+
|
262
|
+
static void bridge_set_period(char * p_in_ns) {
|
263
|
+
int p = (int) strtol(p_in_ns, NULL, 10);
|
264
|
+
period_in_ns = p;
|
265
|
+
bridge_clear_waves_and_pins();
|
266
|
+
}
|
267
|
+
|
268
|
+
|
269
|
+
static bool bridge_is_drive_whole_cycle(Pin * pin) {
|
270
|
+
Wave *wave = &drive_waves[(*pin).drive_wave];
|
271
|
+
|
272
|
+
// If drive wave only has one event
|
273
|
+
if ((*wave).events[1].data == 'T') {
|
274
|
+
// Return true if the single event specifies drive for the whole cycle
|
275
|
+
return (*wave).events[0].data == 'D' &&
|
276
|
+
(*wave).events[0].time == 0;
|
277
|
+
} else {
|
278
|
+
return false;
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
|
283
|
+
/// Immediately drives the given pin to the given value
|
284
|
+
static void bridge_drive_pin(char * index, char * val) {
|
285
|
+
Pin *pin = &pins[atoi(index)];
|
286
|
+
s_vpi_value v = {vpiIntVal, {0}};
|
287
|
+
|
288
|
+
// Apply the data value to the pin's driver
|
289
|
+
v.value.integer = (val[0] - '0');
|
290
|
+
vpi_put_value((*pin).data, &v, NULL, vpiNoDelay);
|
291
|
+
// Make sure not comparing
|
292
|
+
v.value.integer = 0;
|
293
|
+
vpi_put_value((*pin).compare, &v, NULL, vpiNoDelay);
|
294
|
+
|
295
|
+
// Register it as actively driving with it's wave
|
296
|
+
|
297
|
+
// If it is already driving the wave will already be setup
|
298
|
+
if ((*pin).previous_state != 1) {
|
299
|
+
// If the drive is for the whole cycle, then we can enable it here
|
300
|
+
// and don't need a callback
|
301
|
+
if (bridge_is_drive_whole_cycle(pin)) {
|
302
|
+
v.value.integer = 1;
|
303
|
+
vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
|
304
|
+
} else {
|
305
|
+
bridge_enable_drive_wave(pin);
|
306
|
+
}
|
307
|
+
|
308
|
+
if ((*pin).previous_state == 2) {
|
309
|
+
bridge_disable_compare_wave(pin);
|
310
|
+
}
|
311
|
+
(*pin).previous_state = 1;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
|
315
|
+
|
316
|
+
/// Immediately sets the given pin to compare against the given value
|
317
|
+
static void bridge_compare_pin(char * index, char * val) {
|
318
|
+
Pin *pin = &pins[atoi(index)];
|
319
|
+
s_vpi_value v = {vpiIntVal, {0}};
|
320
|
+
|
321
|
+
// Apply the data value to the pin's driver, don't enable compare yet,
|
322
|
+
// the wave will do that later
|
323
|
+
v.value.integer = (val[0] - '0');
|
324
|
+
vpi_put_value((*pin).data, &v, NULL, vpiNoDelay);
|
325
|
+
// Make sure not driving
|
326
|
+
v.value.integer = 0;
|
327
|
+
vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
|
328
|
+
|
329
|
+
// Register it as actively comparing with it's wave
|
330
|
+
|
331
|
+
// If it is already comparing the wave will already be setup
|
332
|
+
if ((*pin).previous_state != 2) {
|
333
|
+
bridge_enable_compare_wave(pin);
|
334
|
+
if ((*pin).previous_state == 1) {
|
335
|
+
bridge_disable_drive_wave(pin);
|
336
|
+
}
|
337
|
+
(*pin).previous_state = 2;
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
|
342
|
+
/// Immediately sets the given pin to capture by registering it for compare
|
343
|
+
/// but with its capture flag set
|
344
|
+
static void bridge_capture_pin(char * index) {
|
345
|
+
Pin *pin = &pins[atoi(index)];
|
346
|
+
(*pin).capture_en = true;
|
347
|
+
bridge_compare_pin(index, "0");
|
348
|
+
}
|
349
|
+
|
350
|
+
|
351
|
+
/// Immediately sets the given pin to stop capture by clearing its capture flag
|
352
|
+
static void bridge_stop_capture_pin(char * index) {
|
353
|
+
Pin *pin = &pins[atoi(index)];
|
354
|
+
(*pin).capture_en = false;
|
355
|
+
}
|
356
|
+
|
357
|
+
|
358
|
+
/// Immediately sets the given pin to don't compare
|
359
|
+
static void bridge_dont_care_pin(char * index) {
|
360
|
+
Pin *pin = &pins[atoi(index)];
|
361
|
+
s_vpi_value v = {vpiIntVal, {0}};
|
362
|
+
|
363
|
+
// Disable drive and compare on the pin's driver
|
364
|
+
v.value.integer = 0;
|
365
|
+
vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
|
366
|
+
vpi_put_value((*pin).compare, &v, NULL, vpiNoDelay);
|
367
|
+
|
368
|
+
if ((*pin).previous_state != 0) {
|
369
|
+
if ((*pin).previous_state == 1) {
|
370
|
+
if (!bridge_is_drive_whole_cycle(pin)) {
|
371
|
+
bridge_disable_drive_wave(pin);
|
372
|
+
}
|
373
|
+
}
|
374
|
+
if ((*pin).previous_state == 2) {
|
375
|
+
bridge_disable_compare_wave(pin);
|
376
|
+
}
|
377
|
+
(*pin).previous_state = 0;
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
|
382
|
+
/// Callback handler to implement the events registered by bridge_register_wave_event
|
383
|
+
PLI_INT32 bridge_apply_wave_event_cb(p_cb_data data) {
|
384
|
+
s_vpi_value v = {vpiIntVal, {0}};
|
385
|
+
s_vpi_value v2 = {vpiIntVal, {0}};
|
386
|
+
|
387
|
+
int * wave_ix = (int*)(&(data->user_data[0]));
|
388
|
+
int * event_ix = (int*)(&(data->user_data[sizeof(int)]));
|
389
|
+
int * compare = (int*)(&(data->user_data[sizeof(int) * 2]));
|
390
|
+
|
391
|
+
Wave * wave;
|
392
|
+
|
393
|
+
if (*compare) {
|
394
|
+
wave = &compare_waves[*wave_ix];
|
395
|
+
|
396
|
+
int d;
|
397
|
+
switch((*wave).events[*event_ix].data) {
|
398
|
+
case 'C' :
|
399
|
+
d = 1;
|
400
|
+
break;
|
401
|
+
case 'X' :
|
402
|
+
d = 0;
|
403
|
+
break;
|
404
|
+
default :
|
405
|
+
vpi_printf("ERROR: Unknown compare event: %c\n", (*wave).events[*event_ix].data);
|
406
|
+
runtime_errors += 1;
|
407
|
+
end_simulation();
|
408
|
+
return 1;
|
409
|
+
}
|
410
|
+
|
411
|
+
v.value.integer = d;
|
412
|
+
for (int i = 0; i < (*wave).active_pin_count; i++) {
|
413
|
+
if ((*(*wave).active_pins[i]).capture_en) {
|
414
|
+
vpi_put_value((*(*wave).active_pins[i]).capture, &v, NULL, vpiNoDelay);
|
415
|
+
} else {
|
416
|
+
vpi_put_value((*(*wave).active_pins[i]).compare, &v, NULL, vpiNoDelay);
|
417
|
+
}
|
418
|
+
}
|
419
|
+
|
420
|
+
|
421
|
+
} else {
|
422
|
+
|
423
|
+
wave = &drive_waves[*wave_ix];
|
424
|
+
|
425
|
+
//vpi_printf("[DEBUG] Apply drive wave %i, event %i, data %c\n", *wave_ix, *event_ix, (*wave).events[*event_ix].data);
|
426
|
+
|
427
|
+
int d;
|
428
|
+
int on;
|
429
|
+
switch((*wave).events[*event_ix].data) {
|
430
|
+
case '0' :
|
431
|
+
d = 1;
|
432
|
+
on = 1;
|
433
|
+
break;
|
434
|
+
case '1' :
|
435
|
+
d = 2;
|
436
|
+
on = 1;
|
437
|
+
break;
|
438
|
+
case 'D' :
|
439
|
+
d = 0;
|
440
|
+
on = 1;
|
441
|
+
break;
|
442
|
+
case 'X' :
|
443
|
+
d = 0;
|
444
|
+
on = 0;
|
445
|
+
break;
|
446
|
+
default :
|
447
|
+
vpi_printf("ERROR: Unknown drive event: %c\n", (*wave).events[*event_ix].data);
|
448
|
+
runtime_errors += 1;
|
449
|
+
end_simulation();
|
450
|
+
return 1;
|
451
|
+
}
|
452
|
+
|
453
|
+
v.value.integer = d;
|
454
|
+
v2.value.integer = on;
|
455
|
+
if (on) {
|
456
|
+
for (int i = 0; i < (*wave).active_pin_count; i++) {
|
457
|
+
vpi_put_value((*(*wave).active_pins[i]).force_data, &v, NULL, vpiNoDelay);
|
458
|
+
vpi_put_value((*(*wave).active_pins[i]).drive, &v2, NULL, vpiNoDelay);
|
459
|
+
}
|
460
|
+
} else {
|
461
|
+
for (int i = 0; i < (*wave).active_pin_count; i++) {
|
462
|
+
vpi_put_value((*(*wave).active_pins[i]).drive, &v2, NULL, vpiNoDelay);
|
463
|
+
}
|
464
|
+
}
|
465
|
+
}
|
466
|
+
|
467
|
+
free(data->user_data);
|
468
|
+
|
469
|
+
return 0;
|
470
|
+
}
|
471
|
+
|
472
|
+
|
473
|
+
/// Registers a callback to apply the given wave during this cycle
|
474
|
+
static void bridge_register_wave_event(int wave_ix, int event_ix, int compare, int delay_in_ns) {
|
475
|
+
s_cb_data call;
|
476
|
+
s_vpi_time time;
|
477
|
+
|
478
|
+
// This will get freed by the callback
|
479
|
+
char * user_data = (char *) malloc((sizeof(int) * 3));
|
480
|
+
|
481
|
+
int * d0 = (int*)(&user_data[0]);
|
482
|
+
int * d1 = (int*)(&user_data[sizeof(int)]);
|
483
|
+
int * d2 = (int*)(&user_data[sizeof(int) * 2]);
|
484
|
+
|
485
|
+
*d0 = wave_ix;
|
486
|
+
*d1 = event_ix;
|
487
|
+
*d2 = compare;
|
488
|
+
|
489
|
+
time.type = vpiSimTime;
|
490
|
+
time.high = (uint32_t)(0);
|
491
|
+
time.low = (uint32_t)(delay_in_ns);
|
492
|
+
|
493
|
+
call.reason = cbAfterDelay;
|
494
|
+
call.cb_rtn = bridge_apply_wave_event_cb;
|
495
|
+
call.obj = 0;
|
496
|
+
call.time = &time;
|
497
|
+
call.value = 0;
|
498
|
+
call.user_data = user_data;
|
499
|
+
|
500
|
+
vpi_free_object(vpi_register_cb(&call));
|
501
|
+
}
|
502
|
+
|
503
|
+
|
504
|
+
/// Entry point to the bridge_wait_for_msg loop
|
505
|
+
PLI_INT32 bridge_init() {
|
506
|
+
client_put("READY!\n");
|
507
|
+
return bridge_wait_for_msg(NULL);
|
508
|
+
}
|
509
|
+
|
510
|
+
|
511
|
+
/// Waits and responds to instructions from Origen (to set pin states).
|
512
|
+
/// When Origen requests a cycle, time will be advanced and this func will be called again.
|
513
|
+
PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
514
|
+
UNUSED(data);
|
515
|
+
int max_msg_len = 100;
|
516
|
+
char msg[max_msg_len];
|
517
|
+
int err;
|
518
|
+
char *opcode, *arg1, *arg2, *arg3, *arg4;
|
519
|
+
vpiHandle handle;
|
520
|
+
s_vpi_value v;
|
521
|
+
|
522
|
+
while(1) {
|
523
|
+
|
524
|
+
err = client_get(max_msg_len, msg);
|
525
|
+
if (err) {
|
526
|
+
vpi_printf("ERROR: Failed to receive from Origen!\n");
|
527
|
+
end_simulation();
|
528
|
+
return 1;
|
529
|
+
}
|
530
|
+
if (runtime_errors) {
|
531
|
+
end_simulation();
|
532
|
+
return 1;
|
533
|
+
}
|
534
|
+
|
535
|
+
if (log_messages) {
|
536
|
+
vpi_printf("[MESSAGE] %s\n", msg);
|
537
|
+
}
|
538
|
+
|
539
|
+
// Keep a copy of the original message, helpful for debugging
|
540
|
+
char* orig_msg = calloc(strlen(msg)+1, sizeof(char));
|
541
|
+
strcpy(orig_msg, msg);
|
542
|
+
|
543
|
+
opcode = strtok(msg, "^");
|
544
|
+
|
545
|
+
switch(*opcode) {
|
546
|
+
// Define pin
|
547
|
+
// 0^pin_name^pin_index^drive_wave_ix^capture_wave_ix
|
548
|
+
//
|
549
|
+
// 0 for the wave indexes means the default, custom waves
|
550
|
+
// must therefore start from index 1
|
551
|
+
//
|
552
|
+
// The pin index must be uniquely assigned to the pin by the caller
|
553
|
+
// and must be less than MAX_NUMBER_PINS
|
554
|
+
//
|
555
|
+
// 0^tdi^12^0^0
|
556
|
+
case '0' :
|
557
|
+
arg1 = strtok(NULL, "^");
|
558
|
+
arg2 = strtok(NULL, "^");
|
559
|
+
arg3 = strtok(NULL, "^");
|
560
|
+
arg4 = strtok(NULL, "^");
|
561
|
+
//DEBUG("Define Pin: %s, %s, %s, %s\n", arg1, arg2, arg3, arg4);
|
562
|
+
bridge_define_pin(arg1, arg2, arg3, arg4);
|
563
|
+
break;
|
564
|
+
// Set Period
|
565
|
+
// 1^100
|
566
|
+
case '1' :
|
567
|
+
arg1 = strtok(NULL, "^");
|
568
|
+
bridge_set_period(arg1);
|
569
|
+
break;
|
570
|
+
// Drive Pin
|
571
|
+
// 2^pin_index^data
|
572
|
+
//
|
573
|
+
// 2^12^0
|
574
|
+
// 2^12^1
|
575
|
+
case '2' :
|
576
|
+
arg1 = strtok(NULL, "^");
|
577
|
+
arg2 = strtok(NULL, "^");
|
578
|
+
//DEBUG("Drive Pin: %s, %s\n", arg1, arg2);
|
579
|
+
bridge_drive_pin(arg1, arg2);
|
580
|
+
break;
|
581
|
+
// Cycle
|
582
|
+
// 3^number_of_cycles
|
583
|
+
//
|
584
|
+
// 3^1
|
585
|
+
// 3^65535
|
586
|
+
case '3' :
|
587
|
+
arg1 = strtok(NULL, "^");
|
588
|
+
repeat = strtol(arg1, NULL, 10);
|
589
|
+
if (repeat) {
|
590
|
+
repeat = repeat - 1;
|
591
|
+
}
|
592
|
+
bridge_cycle();
|
593
|
+
return 0;
|
594
|
+
// Compare Pin
|
595
|
+
// 4^pin_index^data
|
596
|
+
//
|
597
|
+
// 4^14^0
|
598
|
+
// 4^14^1
|
599
|
+
case '4' :
|
600
|
+
arg1 = strtok(NULL, "^");
|
601
|
+
arg2 = strtok(NULL, "^");
|
602
|
+
bridge_compare_pin(arg1, arg2);
|
603
|
+
break;
|
604
|
+
// Don't Care Pin
|
605
|
+
// 5^pin_index
|
606
|
+
//
|
607
|
+
// 5^14
|
608
|
+
case '5' :
|
609
|
+
arg1 = strtok(NULL, "^");
|
610
|
+
bridge_dont_care_pin(arg1);
|
611
|
+
break;
|
612
|
+
// Define wave
|
613
|
+
// 6^wave_index^compare^events
|
614
|
+
//
|
615
|
+
// 0 for the wave indexes means the default, custom waves
|
616
|
+
// must therefore start from index 1
|
617
|
+
//
|
618
|
+
// 0 for the compare parameter means it is a drive wave, 1 means it is
|
619
|
+
// for when the pin is in compare mode
|
620
|
+
//
|
621
|
+
// Some example events are shown below:
|
622
|
+
//
|
623
|
+
// 6^1^0^0_D_25_0_50_D_75_0 // Drive at 0ns, off at 25ns, drive at 50ns, off at 75ns
|
624
|
+
case '6' :
|
625
|
+
arg1 = strtok(NULL, "^");
|
626
|
+
arg2 = strtok(NULL, "^");
|
627
|
+
arg3 = strtok(NULL, "^");
|
628
|
+
//DEBUG("Define Wave: %s, %s, %s\n", arg1, arg2, arg3);
|
629
|
+
bridge_define_wave(arg1, arg2, arg3);
|
630
|
+
break;
|
631
|
+
// Sync-up
|
632
|
+
// 7^
|
633
|
+
case '7' :
|
634
|
+
client_put("OK!\n");
|
635
|
+
break;
|
636
|
+
// Complete
|
637
|
+
// 8^
|
638
|
+
case '8' :
|
639
|
+
end_simulation();
|
640
|
+
return 0;
|
641
|
+
// Peek
|
642
|
+
// Returns the current value of the given net
|
643
|
+
//
|
644
|
+
// 9^origen.debug.errors
|
645
|
+
case '9' :
|
646
|
+
arg1 = strtok(NULL, "^");
|
647
|
+
handle = vpi_handle_by_name(arg1, NULL);
|
648
|
+
if (handle) {
|
649
|
+
v.format = vpiDecStrVal; // Seems important to set this before get
|
650
|
+
vpi_get_value(handle, &v);
|
651
|
+
sprintf(msg, "%s\n", v.value.str);
|
652
|
+
client_put(msg);
|
653
|
+
} else {
|
654
|
+
client_put("FAIL\n");
|
655
|
+
}
|
656
|
+
break;
|
657
|
+
// Set Pattern Name
|
658
|
+
// a^atd_ramp_25mhz
|
659
|
+
case 'a' :
|
660
|
+
handle = vpi_handle_by_name("origen.debug.pattern", NULL);
|
661
|
+
arg1 = strtok(NULL, "^");
|
662
|
+
|
663
|
+
v.format = vpiStringVal;
|
664
|
+
v.value.str = arg1;
|
665
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
666
|
+
break;
|
667
|
+
// Poke
|
668
|
+
// Sets the given value on the given net, the number should be
|
669
|
+
// given as a decimal string
|
670
|
+
//
|
671
|
+
// b^origen.debug.errors^15
|
672
|
+
case 'b' :
|
673
|
+
arg1 = strtok(NULL, "^");
|
674
|
+
arg2 = strtok(NULL, "^");
|
675
|
+
handle = vpi_handle_by_name(arg1, NULL);
|
676
|
+
if (handle) {
|
677
|
+
v.format = vpiDecStrVal;
|
678
|
+
v.value.str = arg2;
|
679
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
680
|
+
}
|
681
|
+
break;
|
682
|
+
// Set Comment
|
683
|
+
// c^Some comment about the pattern
|
684
|
+
case 'c' :
|
685
|
+
handle = vpi_handle_by_name("origen.debug.comments", NULL);
|
686
|
+
arg1 = strtok(NULL, "^");
|
687
|
+
|
688
|
+
v.format = vpiStringVal;
|
689
|
+
v.value.str = arg1;
|
690
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
691
|
+
break;
|
692
|
+
// Log all messages
|
693
|
+
// d^1 Turn logging on
|
694
|
+
// d^0 Turn logging off
|
695
|
+
case 'd' :
|
696
|
+
arg1 = strtok(NULL, "^");
|
697
|
+
log_messages = atoi(arg1);
|
698
|
+
break;
|
699
|
+
// Capture Pin
|
700
|
+
// e^pin_index
|
701
|
+
//
|
702
|
+
// e^14
|
703
|
+
case 'e' :
|
704
|
+
arg1 = strtok(NULL, "^");
|
705
|
+
bridge_capture_pin(arg1);
|
706
|
+
break;
|
707
|
+
// Sync enable
|
708
|
+
case 'f' :
|
709
|
+
handle = vpi_handle_by_name("origen.pins.sync", NULL);
|
710
|
+
v.format = vpiDecStrVal;
|
711
|
+
v.value.str = "1";
|
712
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
713
|
+
break;
|
714
|
+
// Sync disable
|
715
|
+
case 'g' :
|
716
|
+
handle = vpi_handle_by_name("origen.pins.sync", NULL);
|
717
|
+
v.format = vpiDecStrVal;
|
718
|
+
v.value.str = "0";
|
719
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
720
|
+
break;
|
721
|
+
// Stop Capture Pin
|
722
|
+
// h^pin_index
|
723
|
+
//
|
724
|
+
// h^14
|
725
|
+
case 'h' :
|
726
|
+
arg1 = strtok(NULL, "^");
|
727
|
+
bridge_stop_capture_pin(arg1);
|
728
|
+
break;
|
729
|
+
default :
|
730
|
+
vpi_printf("ERROR: Illegal message received from Origen: %s\n", orig_msg);
|
731
|
+
runtime_errors += 1;
|
732
|
+
end_simulation();
|
733
|
+
return 1;
|
734
|
+
}
|
735
|
+
free(orig_msg);
|
736
|
+
}
|
737
|
+
}
|
738
|
+
|
739
|
+
|
740
|
+
static void end_simulation() {
|
741
|
+
vpiHandle handle;
|
742
|
+
s_vpi_value v;
|
743
|
+
|
744
|
+
// Setting this node will cause the testbench to call $finish
|
745
|
+
handle = vpi_handle_by_name("origen.finish", NULL);
|
746
|
+
v.format = vpiDecStrVal;
|
747
|
+
v.value.str = "1";
|
748
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
749
|
+
// Corner case during testing, the timeset may not have been set yet
|
750
|
+
bridge_set_period("1");
|
751
|
+
// Do a cycle so that the simulation sees the edge on origen.finish
|
752
|
+
bridge_cycle();
|
753
|
+
}
|
754
|
+
|
755
|
+
|
756
|
+
PLI_INT32 bridge_cycle_cb(p_cb_data data) {
|
757
|
+
UNUSED(data);
|
758
|
+
repeat = repeat - 1;
|
759
|
+
bridge_cycle();
|
760
|
+
return 0;
|
761
|
+
}
|
762
|
+
|
763
|
+
|
764
|
+
/// Registers a callback after a cycle period, the main server loop should unblock
|
765
|
+
/// after calling this to allow the simulation to proceed for a cycle
|
766
|
+
static void bridge_cycle() {
|
767
|
+
s_cb_data call;
|
768
|
+
s_vpi_time time;
|
769
|
+
|
770
|
+
time.type = vpiSimTime;
|
771
|
+
time.high = (uint32_t)(0);
|
772
|
+
time.low = (uint32_t)(period_in_ns);
|
773
|
+
|
774
|
+
call.reason = cbAfterDelay;
|
775
|
+
call.obj = 0;
|
776
|
+
call.time = &time;
|
777
|
+
call.value = 0;
|
778
|
+
call.user_data = 0;
|
779
|
+
|
780
|
+
//DEBUG("REPEAT: %d\n", repeat);
|
781
|
+
if (repeat) {
|
782
|
+
call.cb_rtn = bridge_cycle_cb;
|
783
|
+
} else {
|
784
|
+
call.cb_rtn = bridge_wait_for_msg;
|
785
|
+
}
|
786
|
+
|
787
|
+
vpi_free_object(vpi_register_cb(&call));
|
788
|
+
|
789
|
+
bridge_register_wave_events();
|
790
|
+
}
|