origen_sim 0.15.0 → 0.16.0
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/application.rb +1 -1
- data/config/shared_commands.rb +13 -4
- data/config/version.rb +1 -1
- data/ext/bridge.c +521 -272
- data/ext/bridge.h +2 -0
- data/ext/defines.h.erb +8 -0
- data/ext/origen.c +2 -0
- data/lib/origen_sim.rb +21 -1
- data/lib/origen_sim/origen/pins/pin.rb +7 -2
- data/lib/origen_sim/origen_testers/api.rb +11 -2
- data/lib/origen_sim/simulation.rb +34 -4
- data/lib/origen_sim/simulator.rb +227 -19
- data/lib/origen_sim/stderr_reader.rb +9 -3
- data/lib/origen_sim/stdout_reader.rb +35 -12
- data/lib/origen_sim/tester.rb +209 -29
- data/lib/origen_sim_dev/dut.rb +31 -29
- data/pattern/test.rb +2 -0
- data/templates/origen_guides/simulation/debugging.md.erb +123 -6
- data/templates/origen_guides/simulation/environment.md.erb +3 -6
- data/templates/origen_guides/simulation/log.md.erb +1 -1
- data/templates/origen_guides/simulation/patterns.md.erb +35 -0
- data/templates/rtl_v/origen.v.erb +14 -49
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43c4c9b46fca49ffc621f5fe6acc1e10c0961db6453c3a67f09e8bc2e0bc233f
|
4
|
+
data.tar.gz: bc825d94eb0859054fbfcd1cb7bbae4c980a8a1b356c489ecbfb2308f0b17697
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 731d4bf00e0f801b08063445a17373dc8d8f48162ed517db8fe154547e7c384e1bbb6b9ab4e4432fb995cc20bd840a0792dc3700e66b3a85cc92d1ee444cc910
|
7
|
+
data.tar.gz: f68c396143c15f87f210d6c94d2d5020bc07d21c2da3a8664b4e85f6c9fcd3c039e82b963e2d539d58d5bd46cd5b5670450f4f5615cb1359dad353d9f3b9a84d
|
data/config/application.rb
CHANGED
@@ -42,7 +42,7 @@ class OrigenSimApplication < Origen::Application
|
|
42
42
|
section.page :flows, heading: "Simulating Flows"
|
43
43
|
section.page :log, heading: "Simulator Log Output"
|
44
44
|
section.page :artifacts, heading: "Artifacts"
|
45
|
-
section.page :debugging, heading: "
|
45
|
+
section.page :debugging, heading: "Debugging"
|
46
46
|
end
|
47
47
|
end
|
48
48
|
}
|
data/config/shared_commands.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
# The requested command is passed in here as @command
|
2
2
|
case @command
|
3
3
|
|
4
|
-
when 'generate'
|
4
|
+
when 'generate', 'program'
|
5
5
|
$use_fast_probe_depth = false
|
6
6
|
@application_options << ["--fast", "Fast simulation, minimum probe depth"]
|
7
7
|
$use_fast_probe_depth = ARGV.include?('--fast')
|
8
8
|
|
9
|
-
@application_options << ["--sim_capture", "Update sim captures (ignored when not running a simulation)"
|
10
|
-
|
9
|
+
@application_options << ["--sim_capture", "Update sim captures (ignored when not running a simulation)", ->(options) {
|
10
|
+
Origen.app!.update_sim_captures = true
|
11
|
+
}]
|
11
12
|
|
12
|
-
@
|
13
|
+
unless @command == 'program'
|
14
|
+
@application_options << ["--flow NAME", "Simulate multiple patterns back-back within a single simulation with the given name", ->(options, name) {
|
15
|
+
OrigenSim.flow = name
|
16
|
+
}]
|
17
|
+
end
|
13
18
|
|
14
19
|
@application_options << ["--socket_dir PATH", "Specify the directory to be used for creating the Origen -> simulator communication socket (/tmp by default) ", ->(options, path) {
|
15
20
|
FileUtils.mkdir_p(path) unless File.exist?(path)
|
@@ -18,6 +23,10 @@ when 'generate'
|
|
18
23
|
OrigenSim.socket_dir = path
|
19
24
|
}]
|
20
25
|
|
26
|
+
@application_options << ["--max_errors VALUE", Integer, "Override the maximum number of errors allowed in a simulation before aborting ", ->(options, value) {
|
27
|
+
OrigenSim.max_errors = value
|
28
|
+
}]
|
29
|
+
|
21
30
|
when "sim:ci", "origen_sim:ci"
|
22
31
|
require "#{Origen.root!}/lib/origen_sim/commands/ci"
|
23
32
|
exit 0
|
data/config/version.rb
CHANGED
data/ext/bridge.c
CHANGED
@@ -10,9 +10,11 @@
|
|
10
10
|
#include <stdio.h>
|
11
11
|
#include <stdbool.h>
|
12
12
|
#include <string.h>
|
13
|
+
#include <stdarg.h>
|
13
14
|
|
14
15
|
#define MAX_NUMBER_PINS 2000
|
15
16
|
#define MAX_WAVE_EVENTS 50
|
17
|
+
#define MAX_TRANSACTION_ERRORS 128
|
16
18
|
|
17
19
|
typedef struct Pin {
|
18
20
|
char *name;
|
@@ -42,8 +44,22 @@ typedef struct Wave {
|
|
42
44
|
int active_pin_count;
|
43
45
|
} Wave;
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
// Used to record a miscompare event that is used by OrigenSim to work out the actual data
|
48
|
+
// from a failed register read transaction
|
49
|
+
typedef struct Miscompare {
|
50
|
+
char *pin_name;
|
51
|
+
unsigned long long cycle;
|
52
|
+
int expected;
|
53
|
+
int received;
|
54
|
+
} Miscompare;
|
55
|
+
|
56
|
+
static Miscompare miscompares[MAX_TRANSACTION_ERRORS];
|
57
|
+
static int transaction_error_count = 0;
|
58
|
+
static bool transaction_open = false;
|
59
|
+
static int match_loop_error_count = 0;
|
60
|
+
static bool match_loop_open = false;
|
61
|
+
static uint64_t period_in_simtime_units;
|
62
|
+
static unsigned long repeat = 0;
|
47
63
|
static Pin pins[MAX_NUMBER_PINS];
|
48
64
|
static int number_of_pins = 0;
|
49
65
|
// Allocate space for a unique wave for each pin, in reality it will be much less
|
@@ -53,27 +69,34 @@ static Wave compare_waves[MAX_NUMBER_PINS];
|
|
53
69
|
static int number_of_compare_waves = 0;
|
54
70
|
static int runtime_errors = 0;
|
55
71
|
static int log_messages = 0;
|
56
|
-
|
57
|
-
static
|
58
|
-
static
|
59
|
-
static
|
60
|
-
static
|
61
|
-
|
62
|
-
static void
|
63
|
-
static void
|
64
|
-
static void
|
65
|
-
static void
|
66
|
-
static void
|
67
|
-
static void
|
68
|
-
static void
|
69
|
-
static void
|
70
|
-
static void
|
71
|
-
static void
|
72
|
-
static void
|
73
|
-
static
|
72
|
+
static int error_count = 0;
|
73
|
+
static int max_errors = 100;
|
74
|
+
static unsigned long long cycle_count = 0;
|
75
|
+
static bool max_errors_exceeded = false;
|
76
|
+
static bool max_errors_exceeded_during_transaction = false;
|
77
|
+
|
78
|
+
static void set_period(char*);
|
79
|
+
static void define_pin(char*, char*, char*, char*);
|
80
|
+
static void define_wave(char*, char*, char*);
|
81
|
+
static void cycle(void);
|
82
|
+
static void drive_pin(char*, char*);
|
83
|
+
static void compare_pin(char*, char*);
|
84
|
+
static void capture_pin(char*);
|
85
|
+
static void stop_capture_pin(char*);
|
86
|
+
static void dont_care_pin(char*);
|
87
|
+
static void register_wave_events(void);
|
88
|
+
static void register_wave_event(int, int, int, uint64_t);
|
89
|
+
static void enable_drive_wave(Pin*);
|
90
|
+
static void disable_drive_wave(Pin*);
|
91
|
+
static void enable_compare_wave(Pin*);
|
92
|
+
static void disable_compare_wave(Pin*);
|
93
|
+
static void clear_waves_and_pins(void);
|
94
|
+
static bool is_drive_whole_cycle(Pin*);
|
95
|
+
static void origen_log(int, const char*, ...);
|
74
96
|
static void end_simulation(void);
|
97
|
+
static void on_max_errors_exceeded(void);
|
75
98
|
|
76
|
-
static void
|
99
|
+
static void define_pin(char * name, char * pin_ix, char * drive_wave_ix, char * compare_wave_ix) {
|
77
100
|
int index = atoi(pin_ix);
|
78
101
|
Pin *pin = &pins[index];
|
79
102
|
number_of_pins += 1;
|
@@ -98,7 +121,7 @@ static void bridge_define_pin(char * name, char * pin_ix, char * drive_wave_ix,
|
|
98
121
|
free(data);
|
99
122
|
|
100
123
|
if (!(*pin).data) {
|
101
|
-
|
124
|
+
origen_log(LOG_WARNING, "Your DUT defines pin '%s', however it is not present in the testbench and will be ignored", (*pin).name);
|
102
125
|
(*pin).present = false;
|
103
126
|
} else {
|
104
127
|
(*pin).present = true;
|
@@ -132,7 +155,7 @@ static void bridge_define_pin(char * name, char * pin_ix, char * drive_wave_ix,
|
|
132
155
|
}
|
133
156
|
|
134
157
|
|
135
|
-
static void
|
158
|
+
static void define_wave(char * index, char * compare, char * events) {
|
136
159
|
int ix = atoi(index);
|
137
160
|
Wave * wave;
|
138
161
|
|
@@ -165,7 +188,7 @@ static void bridge_define_wave(char * index, char * compare, char * events) {
|
|
165
188
|
}
|
166
189
|
|
167
190
|
|
168
|
-
static void
|
191
|
+
static void register_wave_events() {
|
169
192
|
for (int i = 0; i < number_of_drive_waves; i++) {
|
170
193
|
|
171
194
|
if (drive_waves[i].active_pin_count) {
|
@@ -179,7 +202,7 @@ static void bridge_register_wave_events() {
|
|
179
202
|
// TODO: May save some time by calling directly at time 0
|
180
203
|
//if (time == 0) {
|
181
204
|
//} else {
|
182
|
-
|
205
|
+
register_wave_event(i, x, 0, time);
|
183
206
|
//}
|
184
207
|
x++;
|
185
208
|
}
|
@@ -199,7 +222,7 @@ static void bridge_register_wave_events() {
|
|
199
222
|
// TODO: May save some time by calling directly at time 0
|
200
223
|
//if (time == 0) {
|
201
224
|
//} else {
|
202
|
-
|
225
|
+
register_wave_event(i, x, 1, time);
|
203
226
|
//}
|
204
227
|
x++;
|
205
228
|
}
|
@@ -212,7 +235,7 @@ static void bridge_register_wave_events() {
|
|
212
235
|
/// This is done by adding the pin to the wave's active pin list, if the wave has
|
213
236
|
/// at least one pin in its list, the necessary callbacks will get triggered on every
|
214
237
|
/// cycle to implement the required waveform.
|
215
|
-
static void
|
238
|
+
static void enable_drive_wave(Pin * pin) {
|
216
239
|
Wave *wave = &drive_waves[(*pin).drive_wave];
|
217
240
|
|
218
241
|
(*wave).active_pins[(*wave).active_pin_count] = pin;
|
@@ -221,11 +244,11 @@ static void bridge_enable_drive_wave(Pin * pin) {
|
|
221
244
|
}
|
222
245
|
|
223
246
|
|
224
|
-
static void
|
247
|
+
static void disable_drive_wave(Pin * pin) {
|
225
248
|
Wave *wave = &drive_waves[(*pin).drive_wave];
|
226
249
|
|
227
250
|
if ((*wave).active_pin_count == 0) {
|
228
|
-
|
251
|
+
origen_log(LOG_ERROR, "Wanted to disable drive on pin %i, but its drive wave has no active pins!", (*pin).index);
|
229
252
|
end_simulation();
|
230
253
|
}
|
231
254
|
|
@@ -241,7 +264,7 @@ static void bridge_disable_drive_wave(Pin * pin) {
|
|
241
264
|
(*wave).active_pin_count -= 1;
|
242
265
|
}
|
243
266
|
|
244
|
-
static void
|
267
|
+
static void enable_compare_wave(Pin * pin) {
|
245
268
|
Wave *wave = &compare_waves[(*pin).compare_wave];
|
246
269
|
|
247
270
|
(*wave).active_pins[(*wave).active_pin_count] = pin;
|
@@ -249,7 +272,7 @@ static void bridge_enable_compare_wave(Pin * pin) {
|
|
249
272
|
(*wave).active_pin_count += 1;
|
250
273
|
}
|
251
274
|
|
252
|
-
static void
|
275
|
+
static void disable_compare_wave(Pin * pin) {
|
253
276
|
Wave *wave = &compare_waves[(*pin).compare_wave];
|
254
277
|
|
255
278
|
// If pin is last, we can clear it by just decrementing the active pin counter
|
@@ -265,7 +288,7 @@ static void bridge_disable_compare_wave(Pin * pin) {
|
|
265
288
|
}
|
266
289
|
|
267
290
|
|
268
|
-
static void
|
291
|
+
static void clear_waves_and_pins() {
|
269
292
|
for (int i = 0; i < number_of_pins; i++) {
|
270
293
|
Pin *pin = &pins[i];
|
271
294
|
free((*pin).name);
|
@@ -276,14 +299,14 @@ static void bridge_clear_waves_and_pins() {
|
|
276
299
|
}
|
277
300
|
|
278
301
|
|
279
|
-
static void
|
280
|
-
uint64_t p = (uint64_t) strtol(
|
281
|
-
|
282
|
-
|
302
|
+
static void set_period(char * p_in_simtime_units_str) {
|
303
|
+
uint64_t p = (uint64_t) strtol(p_in_simtime_units_str, NULL, 10);
|
304
|
+
period_in_simtime_units = p;
|
305
|
+
clear_waves_and_pins();
|
283
306
|
}
|
284
307
|
|
285
308
|
|
286
|
-
static bool
|
309
|
+
static bool is_drive_whole_cycle(Pin * pin) {
|
287
310
|
Wave *wave = &drive_waves[(*pin).drive_wave];
|
288
311
|
|
289
312
|
// If drive wave only has one event
|
@@ -298,7 +321,7 @@ static bool bridge_is_drive_whole_cycle(Pin * pin) {
|
|
298
321
|
|
299
322
|
|
300
323
|
/// Immediately drives the given pin to the given value
|
301
|
-
static void
|
324
|
+
static void drive_pin(char * index, char * val) {
|
302
325
|
Pin *pin = &pins[atoi(index)];
|
303
326
|
s_vpi_value v = {vpiIntVal, {0}};
|
304
327
|
|
@@ -316,15 +339,15 @@ static void bridge_drive_pin(char * index, char * val) {
|
|
316
339
|
if ((*pin).previous_state != 1) {
|
317
340
|
// If the drive is for the whole cycle, then we can enable it here
|
318
341
|
// and don't need a callback
|
319
|
-
if (
|
342
|
+
if (is_drive_whole_cycle(pin)) {
|
320
343
|
v.value.integer = 1;
|
321
344
|
vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
|
322
345
|
} else {
|
323
|
-
|
346
|
+
enable_drive_wave(pin);
|
324
347
|
}
|
325
348
|
|
326
349
|
if ((*pin).previous_state == 2) {
|
327
|
-
|
350
|
+
disable_compare_wave(pin);
|
328
351
|
}
|
329
352
|
(*pin).previous_state = 1;
|
330
353
|
}
|
@@ -333,7 +356,7 @@ static void bridge_drive_pin(char * index, char * val) {
|
|
333
356
|
|
334
357
|
|
335
358
|
/// Immediately sets the given pin to compare against the given value
|
336
|
-
static void
|
359
|
+
static void compare_pin(char * index, char * val) {
|
337
360
|
Pin *pin = &pins[atoi(index)];
|
338
361
|
s_vpi_value v = {vpiIntVal, {0}};
|
339
362
|
|
@@ -350,10 +373,10 @@ static void bridge_compare_pin(char * index, char * val) {
|
|
350
373
|
|
351
374
|
// If it is already comparing the wave will already be setup
|
352
375
|
if ((*pin).previous_state != 2) {
|
353
|
-
|
376
|
+
enable_compare_wave(pin);
|
354
377
|
if ((*pin).previous_state == 1) {
|
355
|
-
if (!
|
356
|
-
|
378
|
+
if (!is_drive_whole_cycle(pin)) {
|
379
|
+
disable_drive_wave(pin);
|
357
380
|
}
|
358
381
|
}
|
359
382
|
(*pin).previous_state = 2;
|
@@ -364,22 +387,22 @@ static void bridge_compare_pin(char * index, char * val) {
|
|
364
387
|
|
365
388
|
/// Immediately sets the given pin to capture by registering it for compare
|
366
389
|
/// but with its capture flag set
|
367
|
-
static void
|
390
|
+
static void capture_pin(char * index) {
|
368
391
|
Pin *pin = &pins[atoi(index)];
|
369
392
|
(*pin).capture_en = true;
|
370
|
-
|
393
|
+
compare_pin(index, "0");
|
371
394
|
}
|
372
395
|
|
373
396
|
|
374
397
|
/// Immediately sets the given pin to stop capture by clearing its capture flag
|
375
|
-
static void
|
398
|
+
static void stop_capture_pin(char * index) {
|
376
399
|
Pin *pin = &pins[atoi(index)];
|
377
400
|
(*pin).capture_en = false;
|
378
401
|
}
|
379
402
|
|
380
403
|
|
381
404
|
/// Immediately sets the given pin to don't compare
|
382
|
-
static void
|
405
|
+
static void dont_care_pin(char * index) {
|
383
406
|
Pin *pin = &pins[atoi(index)];
|
384
407
|
s_vpi_value v = {vpiIntVal, {0}};
|
385
408
|
|
@@ -391,12 +414,12 @@ static void bridge_dont_care_pin(char * index) {
|
|
391
414
|
|
392
415
|
if ((*pin).previous_state != 0) {
|
393
416
|
if ((*pin).previous_state == 1) {
|
394
|
-
if (!
|
395
|
-
|
417
|
+
if (!is_drive_whole_cycle(pin)) {
|
418
|
+
disable_drive_wave(pin);
|
396
419
|
}
|
397
420
|
}
|
398
421
|
if ((*pin).previous_state == 2) {
|
399
|
-
|
422
|
+
disable_compare_wave(pin);
|
400
423
|
}
|
401
424
|
(*pin).previous_state = 0;
|
402
425
|
}
|
@@ -404,8 +427,8 @@ static void bridge_dont_care_pin(char * index) {
|
|
404
427
|
}
|
405
428
|
|
406
429
|
|
407
|
-
/// Callback handler to implement the events registered by
|
408
|
-
PLI_INT32
|
430
|
+
/// Callback handler to implement the events registered by register_wave_event
|
431
|
+
PLI_INT32 apply_wave_event_cb(p_cb_data data) {
|
409
432
|
s_vpi_value v = {vpiIntVal, {0}};
|
410
433
|
s_vpi_value v2 = {vpiIntVal, {0}};
|
411
434
|
|
@@ -427,7 +450,7 @@ PLI_INT32 bridge_apply_wave_event_cb(p_cb_data data) {
|
|
427
450
|
d = 0;
|
428
451
|
break;
|
429
452
|
default :
|
430
|
-
|
453
|
+
origen_log(LOG_ERROR, "Unknown compare event: %c", (*wave).events[*event_ix].data);
|
431
454
|
runtime_errors += 1;
|
432
455
|
end_simulation();
|
433
456
|
return 1;
|
@@ -469,7 +492,7 @@ PLI_INT32 bridge_apply_wave_event_cb(p_cb_data data) {
|
|
469
492
|
on = 0;
|
470
493
|
break;
|
471
494
|
default :
|
472
|
-
|
495
|
+
origen_log(LOG_ERROR, "Unknown drive event: %c\n", (*wave).events[*event_ix].data);
|
473
496
|
runtime_errors += 1;
|
474
497
|
end_simulation();
|
475
498
|
return 1;
|
@@ -496,7 +519,7 @@ PLI_INT32 bridge_apply_wave_event_cb(p_cb_data data) {
|
|
496
519
|
|
497
520
|
|
498
521
|
/// Registers a callback to apply the given wave during this cycle
|
499
|
-
static void
|
522
|
+
static void register_wave_event(int wave_ix, int event_ix, int compare, uint64_t delay_in_simtime_units) {
|
500
523
|
s_cb_data call;
|
501
524
|
s_vpi_time time;
|
502
525
|
|
@@ -513,11 +536,11 @@ static void bridge_register_wave_event(int wave_ix, int event_ix, int compare, u
|
|
513
536
|
|
514
537
|
time.type = vpiSimTime;
|
515
538
|
|
516
|
-
time.high = (uint32_t)(
|
517
|
-
time.low = (uint32_t)(
|
539
|
+
time.high = (uint32_t)(delay_in_simtime_units >> 32);
|
540
|
+
time.low = (uint32_t)(delay_in_simtime_units);
|
518
541
|
|
519
542
|
call.reason = cbAfterDelay;
|
520
|
-
call.cb_rtn =
|
543
|
+
call.cb_rtn = apply_wave_event_cb;
|
521
544
|
call.obj = 0;
|
522
545
|
call.time = &time;
|
523
546
|
call.value = 0;
|
@@ -534,6 +557,28 @@ PLI_INT32 bridge_init() {
|
|
534
557
|
}
|
535
558
|
|
536
559
|
|
560
|
+
/// Send output to the Origen log, this will be automatically timestamped to the simulation and
|
561
|
+
/// sprintf type arguments can be supplied when calling:
|
562
|
+
///
|
563
|
+
/// origen_log(LOG_ERROR, "Wanted to disable drive on pin %i, but its drive wave has no active pins!", (*pin).index);
|
564
|
+
/// origen_log(LOG_INFO, "Something to tell you about");
|
565
|
+
static void origen_log(int type, const char * fmt, ...) {
|
566
|
+
s_vpi_time now;
|
567
|
+
int max_msg_len = 2048;
|
568
|
+
char msg[max_msg_len];
|
569
|
+
va_list aptr;
|
570
|
+
|
571
|
+
now.type = vpiSimTime;
|
572
|
+
vpi_get_time(0, &now);
|
573
|
+
|
574
|
+
va_start(aptr, fmt);
|
575
|
+
vsprintf(msg, fmt, aptr);
|
576
|
+
va_end(aptr);
|
577
|
+
|
578
|
+
vpi_printf("!%d![%u,%u] %s\n", type, now.high, now.low, msg);
|
579
|
+
};
|
580
|
+
|
581
|
+
|
537
582
|
/// Waits and responds to instructions from Origen (to set pin states).
|
538
583
|
/// When Origen requests a cycle, time will be advanced and this func will be called again.
|
539
584
|
PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
@@ -542,6 +587,8 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
|
542
587
|
char msg[max_msg_len];
|
543
588
|
char comment[128];
|
544
589
|
int err;
|
590
|
+
int timescale;
|
591
|
+
int type;
|
545
592
|
char *opcode, *arg1, *arg2, *arg3, *arg4;
|
546
593
|
vpiHandle handle;
|
547
594
|
s_vpi_value v;
|
@@ -550,6 +597,7 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
|
550
597
|
|
551
598
|
err = client_get(max_msg_len, msg);
|
552
599
|
if (err) {
|
600
|
+
// Don't send to the Origen log since Origen may not be there
|
553
601
|
vpi_printf("ERROR: Failed to receive from Origen!\n");
|
554
602
|
end_simulation();
|
555
603
|
return 1;
|
@@ -569,211 +617,317 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
|
569
617
|
|
570
618
|
opcode = strtok(msg, "^");
|
571
619
|
|
572
|
-
|
573
|
-
//
|
574
|
-
//
|
575
|
-
//
|
576
|
-
//
|
577
|
-
|
578
|
-
//
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
//
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
//
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
620
|
+
if (!max_errors_exceeded || (max_errors_exceeded && (
|
621
|
+
// When max_errors_exceeded, only continue to process the following opcodes.
|
622
|
+
// These are the ones required to enable a controlled shutdown driven by the main Origen process
|
623
|
+
// and also any that return data to Origen so that the main process does not get blocked:
|
624
|
+
// Sync-up End Simulation Peek Flush Log
|
625
|
+
*opcode == '7' || *opcode == '8' || *opcode == '9' || *opcode == 'j' || *opcode == 'k' ||
|
626
|
+
// Get version Get timescale Read reg trans Get cycle count
|
627
|
+
*opcode == 'i' || *opcode == 'l' || *opcode == 'n' || *opcode == 'o'
|
628
|
+
))) {
|
629
|
+
switch(*opcode) {
|
630
|
+
// Define pin
|
631
|
+
// 0^pin_name^pin_index^drive_wave_ix^capture_wave_ix
|
632
|
+
//
|
633
|
+
// 0 for the wave indexes means the default, custom waves
|
634
|
+
// must therefore start from index 1
|
635
|
+
//
|
636
|
+
// The pin index must be uniquely assigned to the pin by the caller
|
637
|
+
// and must be less than MAX_NUMBER_PINS
|
638
|
+
//
|
639
|
+
// 0^tdi^12^0^0
|
640
|
+
case '0' :
|
641
|
+
arg1 = strtok(NULL, "^");
|
642
|
+
arg2 = strtok(NULL, "^");
|
643
|
+
arg3 = strtok(NULL, "^");
|
644
|
+
arg4 = strtok(NULL, "^");
|
645
|
+
//DEBUG("Define Pin: %s, %s, %s, %s\n", arg1, arg2, arg3, arg4);
|
646
|
+
define_pin(arg1, arg2, arg3, arg4);
|
647
|
+
break;
|
648
|
+
// Set Period
|
649
|
+
// 1^100000
|
650
|
+
case '1' :
|
651
|
+
arg1 = strtok(NULL, "^");
|
652
|
+
set_period(arg1);
|
653
|
+
break;
|
654
|
+
// Drive Pin
|
655
|
+
// 2^pin_index^data
|
656
|
+
//
|
657
|
+
// 2^12^0
|
658
|
+
// 2^12^1
|
659
|
+
case '2' :
|
660
|
+
arg1 = strtok(NULL, "^");
|
661
|
+
arg2 = strtok(NULL, "^");
|
662
|
+
//DEBUG("Drive Pin: %s, %s\n", arg1, arg2);
|
663
|
+
drive_pin(arg1, arg2);
|
664
|
+
break;
|
665
|
+
// Cycle
|
666
|
+
// 3^number_of_cycles
|
667
|
+
//
|
668
|
+
// 3^1
|
669
|
+
// 3^65535
|
670
|
+
case '3' :
|
671
|
+
arg1 = strtok(NULL, "^");
|
672
|
+
repeat = strtol(arg1, NULL, 10);
|
673
|
+
if (repeat) {
|
674
|
+
repeat = repeat - 1;
|
675
|
+
}
|
676
|
+
cycle();
|
677
|
+
return 0;
|
678
|
+
// Compare Pin
|
679
|
+
// 4^pin_index^data
|
680
|
+
//
|
681
|
+
// 4^14^0
|
682
|
+
// 4^14^1
|
683
|
+
case '4' :
|
684
|
+
arg1 = strtok(NULL, "^");
|
685
|
+
arg2 = strtok(NULL, "^");
|
686
|
+
compare_pin(arg1, arg2);
|
687
|
+
break;
|
688
|
+
// Don't Care Pin
|
689
|
+
// 5^pin_index
|
690
|
+
//
|
691
|
+
// 5^14
|
692
|
+
case '5' :
|
693
|
+
arg1 = strtok(NULL, "^");
|
694
|
+
dont_care_pin(arg1);
|
695
|
+
break;
|
696
|
+
// Define wave
|
697
|
+
// 6^wave_index^compare^events
|
698
|
+
//
|
699
|
+
// 0 for the wave indexes means the default, custom waves
|
700
|
+
// must therefore start from index 1
|
701
|
+
//
|
702
|
+
// 0 for the compare parameter means it is a drive wave, 1 means it is
|
703
|
+
// for when the pin is in compare mode
|
704
|
+
//
|
705
|
+
// Some example events are shown below:
|
706
|
+
//
|
707
|
+
// 6^1^0^0_D_25_0_50_D_75_0 // Drive at 0ns, off at 25ns, drive at 50ns, off at 75ns
|
708
|
+
case '6' :
|
709
|
+
arg1 = strtok(NULL, "^");
|
710
|
+
arg2 = strtok(NULL, "^");
|
711
|
+
arg3 = strtok(NULL, "^");
|
712
|
+
//DEBUG("Define Wave: %s, %s, %s\n", arg1, arg2, arg3);
|
713
|
+
define_wave(arg1, arg2, arg3);
|
714
|
+
break;
|
715
|
+
// Sync-up
|
716
|
+
// 7^
|
717
|
+
case '7' :
|
718
|
+
client_put("OK!\n");
|
719
|
+
break;
|
720
|
+
// Complete
|
721
|
+
// 8^
|
722
|
+
case '8' :
|
723
|
+
end_simulation();
|
724
|
+
return 0;
|
725
|
+
// Peek
|
726
|
+
// Returns the current value of the given net
|
727
|
+
//
|
728
|
+
// 9^origen.debug.errors
|
729
|
+
case '9' :
|
730
|
+
arg1 = strtok(NULL, "^");
|
731
|
+
handle = vpi_handle_by_name(arg1, NULL);
|
732
|
+
if (handle) {
|
733
|
+
//v.format = vpiDecStrVal; // Seems important to set this before get
|
734
|
+
v.format = vpiBinStrVal;
|
735
|
+
vpi_get_value(handle, &v);
|
736
|
+
//DEBUG("%s\n", v.value.str);
|
737
|
+
sprintf(msg, "%s\n", v.value.str);
|
738
|
+
client_put(msg);
|
739
|
+
} else {
|
740
|
+
client_put("FAIL\n");
|
741
|
+
}
|
742
|
+
break;
|
743
|
+
// Set Pattern Name
|
744
|
+
// a^atd_ramp_25mhz
|
745
|
+
case 'a' :
|
746
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("debug.pattern"), NULL);
|
747
|
+
arg1 = strtok(NULL, "^");
|
748
|
+
|
749
|
+
v.format = vpiStringVal;
|
750
|
+
v.value.str = arg1;
|
751
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
752
|
+
break;
|
753
|
+
// Poke
|
754
|
+
// Sets the given value on the given net, the number should be
|
755
|
+
// given as a decimal string
|
756
|
+
//
|
757
|
+
// b^origen.debug.errors^15
|
758
|
+
case 'b' :
|
759
|
+
arg1 = strtok(NULL, "^");
|
760
|
+
arg2 = strtok(NULL, "^");
|
761
|
+
handle = vpi_handle_by_name(arg1, NULL);
|
762
|
+
if (handle) {
|
763
|
+
v.format = vpiDecStrVal;
|
764
|
+
v.value.str = arg2;
|
765
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
766
|
+
}
|
767
|
+
break;
|
768
|
+
// Set Comment
|
769
|
+
// c^0^Some comment about the pattern
|
770
|
+
case 'c' :
|
771
|
+
arg1 = strtok(NULL, "^");
|
772
|
+
arg2 = strtok(NULL, "^");
|
773
|
+
|
774
|
+
strcpy(comment, ORIGEN_SIM_TESTBENCH_CAT("debug.comments"));
|
775
|
+
strcat(comment, arg1);
|
776
|
+
|
777
|
+
handle = vpi_handle_by_name(comment, NULL);
|
778
|
+
|
779
|
+
v.format = vpiStringVal;
|
707
780
|
v.value.str = arg2;
|
708
781
|
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
782
|
+
break;
|
783
|
+
// Log all messages
|
784
|
+
// d^1 Turn logging on
|
785
|
+
// d^0 Turn logging off
|
786
|
+
case 'd' :
|
787
|
+
arg1 = strtok(NULL, "^");
|
788
|
+
log_messages = atoi(arg1);
|
789
|
+
break;
|
790
|
+
// Capture Pin
|
791
|
+
// e^pin_index
|
792
|
+
//
|
793
|
+
// e^14
|
794
|
+
case 'e' :
|
795
|
+
arg1 = strtok(NULL, "^");
|
796
|
+
capture_pin(arg1);
|
797
|
+
break;
|
798
|
+
// Sync enable
|
799
|
+
case 'f' :
|
800
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins.sync"), NULL);
|
801
|
+
v.format = vpiDecStrVal;
|
802
|
+
v.value.str = "1";
|
803
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
804
|
+
break;
|
805
|
+
// Sync disable
|
806
|
+
case 'g' :
|
807
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins.sync"), NULL);
|
808
|
+
v.format = vpiDecStrVal;
|
809
|
+
v.value.str = "0";
|
810
|
+
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
811
|
+
break;
|
812
|
+
// Stop Capture Pin
|
813
|
+
// h^pin_index
|
814
|
+
//
|
815
|
+
// h^14
|
816
|
+
case 'h' :
|
817
|
+
arg1 = strtok(NULL, "^");
|
818
|
+
stop_capture_pin(arg1);
|
819
|
+
break;
|
820
|
+
// Get version, returns the version of OrigenSim the DUT object was compiled with
|
821
|
+
// i^
|
822
|
+
case 'i' :
|
823
|
+
client_put(ORIGEN_SIM_VERSION"\n");
|
824
|
+
break;
|
825
|
+
// Flush
|
826
|
+
case 'j' :
|
827
|
+
vpi_flush();
|
828
|
+
break;
|
829
|
+
// Log message
|
830
|
+
// k^2^A message to output to the console/log
|
831
|
+
case 'k' :
|
832
|
+
arg1 = strtok(NULL, "^");
|
833
|
+
arg2 = strtok(NULL, "^");
|
834
|
+
type = atoi(arg1);
|
835
|
+
origen_log(type, arg2);
|
836
|
+
break;
|
837
|
+
// Get timescale, returns a number that maps as follows:
|
838
|
+
// -15 - fs
|
839
|
+
// -14 - 10fs
|
840
|
+
// -13 - 100fs
|
841
|
+
// -12 - ps
|
842
|
+
// -11 - 10ps
|
843
|
+
// -10 - 100ps
|
844
|
+
// -9 - ns
|
845
|
+
// -8 - 10ns
|
846
|
+
// -7 - 100ns
|
847
|
+
// -6 - us
|
848
|
+
// -5 - 10us
|
849
|
+
// -4 - 100us
|
850
|
+
// -3 - ms
|
851
|
+
// -2 - 10ms
|
852
|
+
// -1 - 100ms
|
853
|
+
// 0 - s
|
854
|
+
// 1 - 10s
|
855
|
+
// 2 - 100s
|
856
|
+
// l^
|
857
|
+
case 'l' :
|
858
|
+
timescale = vpi_get(vpiTimeUnit, 0);
|
859
|
+
sprintf(msg, "%d\n", timescale);
|
860
|
+
client_put(msg);
|
861
|
+
break;
|
862
|
+
// Set max_errors
|
863
|
+
// m^10
|
864
|
+
case 'm' :
|
865
|
+
arg1 = strtok(NULL, "^");
|
866
|
+
max_errors = atoi(arg1);
|
867
|
+
break;
|
868
|
+
// Read reg transaction
|
869
|
+
// n^1 - Start transaction
|
870
|
+
// n^0 - Stop transaction
|
871
|
+
case 'n' :
|
872
|
+
arg1 = strtok(NULL, "^");
|
873
|
+
|
874
|
+
if (*arg1 == '1') {
|
875
|
+
transaction_error_count = 0;
|
876
|
+
transaction_open = true;
|
877
|
+
} else {
|
878
|
+
// Send Origen the error data
|
879
|
+
sprintf(msg, "%d,%d\n", transaction_error_count, MAX_TRANSACTION_ERRORS);
|
880
|
+
client_put(msg);
|
881
|
+
for (int i = 0; i < transaction_error_count; i++) {
|
882
|
+
Miscompare *m = &miscompares[i];
|
883
|
+
|
884
|
+
sprintf(msg, "%s,%llu,%d,%d\n", (*m).pin_name, (*m).cycle, (*m).expected, (*m).received);
|
885
|
+
client_put(msg);
|
886
|
+
|
887
|
+
free((*m).pin_name);
|
888
|
+
}
|
889
|
+
transaction_open = false;
|
890
|
+
if (max_errors_exceeded_during_transaction) {
|
891
|
+
on_max_errors_exceeded();
|
892
|
+
}
|
893
|
+
}
|
894
|
+
break;
|
895
|
+
// Get cycle count
|
896
|
+
// o^
|
897
|
+
case 'o' :
|
898
|
+
sprintf(msg, "%llu\n", cycle_count);
|
899
|
+
client_put(msg);
|
900
|
+
break;
|
901
|
+
// Set cycle count
|
902
|
+
// p^100
|
903
|
+
case 'p' :
|
904
|
+
arg1 = strtok(NULL, "^");
|
905
|
+
cycle_count = atoll(arg1);
|
906
|
+
break;
|
907
|
+
// Match loop
|
908
|
+
// q^1 - Start match loop
|
909
|
+
// q^0 - Stop match loop
|
910
|
+
case 'q' :
|
911
|
+
arg1 = strtok(NULL, "^");
|
912
|
+
|
913
|
+
if (*arg1 == '1') {
|
914
|
+
match_loop_error_count = 0;
|
915
|
+
match_loop_open = true;
|
916
|
+
} else {
|
917
|
+
match_loop_open = false;
|
918
|
+
}
|
919
|
+
break;
|
920
|
+
default :
|
921
|
+
origen_log(LOG_ERROR, "Illegal message received from Origen: %s", orig_msg);
|
922
|
+
runtime_errors += 1;
|
923
|
+
end_simulation();
|
924
|
+
return 1;
|
925
|
+
}
|
926
|
+
} else {
|
927
|
+
// Simulation has been aborted but not told to end yet by Origen
|
928
|
+
repeat = 0;
|
929
|
+
set_period("1");
|
930
|
+
cycle();
|
777
931
|
}
|
778
932
|
free(orig_msg);
|
779
933
|
}
|
@@ -790,29 +944,31 @@ static void end_simulation() {
|
|
790
944
|
v.value.str = "1";
|
791
945
|
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
792
946
|
// Corner case during testing, the timeset may not have been set yet
|
793
|
-
|
947
|
+
set_period("1");
|
794
948
|
// Do a cycle so that the simulation sees the edge on origen.finish
|
795
|
-
|
949
|
+
cycle();
|
796
950
|
}
|
797
951
|
|
798
952
|
|
799
|
-
PLI_INT32
|
953
|
+
PLI_INT32 cycle_cb(p_cb_data data) {
|
800
954
|
UNUSED(data);
|
801
955
|
repeat = repeat - 1;
|
802
|
-
|
956
|
+
cycle();
|
803
957
|
return 0;
|
804
958
|
}
|
805
959
|
|
806
960
|
|
807
961
|
/// Registers a callback after a cycle period, the main server loop should unblock
|
808
962
|
/// after calling this to allow the simulation to proceed for a cycle
|
809
|
-
static void
|
963
|
+
static void cycle() {
|
810
964
|
s_cb_data call;
|
811
965
|
s_vpi_time time;
|
812
966
|
|
813
967
|
time.type = vpiSimTime;
|
814
|
-
time.high = (uint32_t)(
|
815
|
-
time.low = (uint32_t)(
|
968
|
+
time.high = (uint32_t)(period_in_simtime_units >> 32);
|
969
|
+
time.low = (uint32_t)(period_in_simtime_units);
|
970
|
+
|
971
|
+
cycle_count++;
|
816
972
|
|
817
973
|
call.reason = cbAfterDelay;
|
818
974
|
call.obj = 0;
|
@@ -822,12 +978,105 @@ static void bridge_cycle() {
|
|
822
978
|
|
823
979
|
//DEBUG("REPEAT: %d\n", repeat);
|
824
980
|
if (repeat) {
|
825
|
-
call.cb_rtn =
|
981
|
+
call.cb_rtn = cycle_cb;
|
826
982
|
} else {
|
827
983
|
call.cb_rtn = bridge_wait_for_msg;
|
828
984
|
}
|
829
985
|
|
830
986
|
vpi_free_object(vpi_register_cb(&call));
|
831
987
|
|
832
|
-
|
988
|
+
register_wave_events();
|
989
|
+
}
|
990
|
+
|
991
|
+
static void on_max_errors_exceeded() {
|
992
|
+
// This will cause the simulation to stop processing messages from Origen
|
993
|
+
max_errors_exceeded = true;
|
994
|
+
// And this let's the Origen process know that we have stopped processing
|
995
|
+
origen_log(LOG_ERROR, "!MAX_ERROR_ABORT!");
|
996
|
+
}
|
997
|
+
|
998
|
+
/// Called every time a miscompare event occurs, 3 args will be passed in:
|
999
|
+
/// the pin name, expected data, actual data
|
1000
|
+
PLI_INT32 bridge_on_miscompare(PLI_BYTE8 * user_dat) {
|
1001
|
+
char *pin_name;
|
1002
|
+
int expected;
|
1003
|
+
int received;
|
1004
|
+
s_vpi_value val;
|
1005
|
+
vpiHandle handle;
|
1006
|
+
|
1007
|
+
if (match_loop_open) {
|
1008
|
+
match_loop_error_count++;
|
1009
|
+
|
1010
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("debug.match_errors"), NULL);
|
1011
|
+
val.format = vpiIntVal;
|
1012
|
+
val.value.integer = match_loop_error_count;
|
1013
|
+
vpi_put_value(handle, &val, NULL, vpiNoDelay);
|
1014
|
+
|
1015
|
+
} else {
|
1016
|
+
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
1017
|
+
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
1018
|
+
vpiHandle arg;
|
1019
|
+
|
1020
|
+
arg = vpi_scan(argv);
|
1021
|
+
val.format = vpiStringVal;
|
1022
|
+
vpi_get_value(arg, &val);
|
1023
|
+
pin_name = val.value.str;
|
1024
|
+
|
1025
|
+
arg = vpi_scan(argv);
|
1026
|
+
val.format = vpiIntVal;
|
1027
|
+
vpi_get_value(arg, &val);
|
1028
|
+
expected = val.value.integer;
|
1029
|
+
|
1030
|
+
arg = vpi_scan(argv);
|
1031
|
+
val.format = vpiIntVal;
|
1032
|
+
vpi_get_value(arg, &val);
|
1033
|
+
received = val.value.integer;
|
1034
|
+
|
1035
|
+
vpi_free_object(argv);
|
1036
|
+
|
1037
|
+
origen_log(LOG_ERROR, "Miscompare on pin %s, expected %d received %d", pin_name, expected, received);
|
1038
|
+
|
1039
|
+
error_count++;
|
1040
|
+
|
1041
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("debug.errors"), NULL);
|
1042
|
+
val.format = vpiIntVal;
|
1043
|
+
val.value.integer = error_count;
|
1044
|
+
vpi_put_value(handle, &val, NULL, vpiNoDelay);
|
1045
|
+
|
1046
|
+
if (error_count > max_errors) {
|
1047
|
+
// If a transaction is currently open hold off aborting until after that has completed
|
1048
|
+
// to enable a proper error message to be generated for it
|
1049
|
+
if (transaction_open) {
|
1050
|
+
max_errors_exceeded_during_transaction = true;
|
1051
|
+
} else {
|
1052
|
+
on_max_errors_exceeded();
|
1053
|
+
}
|
1054
|
+
}
|
1055
|
+
|
1056
|
+
// Store all errors during a transaction
|
1057
|
+
if (transaction_open) {
|
1058
|
+
if (transaction_error_count < MAX_TRANSACTION_ERRORS) {
|
1059
|
+
Miscompare *miscompare = &miscompares[transaction_error_count];
|
1060
|
+
|
1061
|
+
(*miscompare).pin_name = malloc(strlen(pin_name) + 1);
|
1062
|
+
strcpy((*miscompare).pin_name, pin_name);
|
1063
|
+
(*miscompare).cycle = cycle_count;
|
1064
|
+
(*miscompare).expected = expected;
|
1065
|
+
(*miscompare).received = received;
|
1066
|
+
}
|
1067
|
+
transaction_error_count++;
|
1068
|
+
}
|
1069
|
+
}
|
1070
|
+
return 0;
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
/// Defines which functions are callable from Verilog as system tasks
|
1074
|
+
void bridge_register_system_tasks() {
|
1075
|
+
s_vpi_systf_data tf_data;
|
1076
|
+
|
1077
|
+
tf_data.type = vpiSysTask;
|
1078
|
+
tf_data.tfname = "$bridge_on_miscompare";
|
1079
|
+
tf_data.calltf = bridge_on_miscompare;
|
1080
|
+
tf_data.compiletf = 0;
|
1081
|
+
vpi_register_systf(&tf_data);
|
833
1082
|
}
|