HDLRuby 2.0.8
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 +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/HDLRuby.gemspec +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +2774 -0
- data/README.pdf +0 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/hdrcc +3 -0
- data/lib/HDLRuby/alcc.rb +137 -0
- data/lib/HDLRuby/backend/hruby_allocator.rb +69 -0
- data/lib/HDLRuby/backend/hruby_c_allocator.rb +76 -0
- data/lib/HDLRuby/hdr_samples/adder.rb +7 -0
- data/lib/HDLRuby/hdr_samples/adder_assign_error.rb +11 -0
- data/lib/HDLRuby/hdr_samples/adder_bench.rb +27 -0
- data/lib/HDLRuby/hdr_samples/adder_gen.rb +7 -0
- data/lib/HDLRuby/hdr_samples/adder_nodef_error.rb +7 -0
- data/lib/HDLRuby/hdr_samples/addsub.rb +19 -0
- data/lib/HDLRuby/hdr_samples/addsubz.rb +22 -0
- data/lib/HDLRuby/hdr_samples/alu.rb +47 -0
- data/lib/HDLRuby/hdr_samples/calculator.rb +48 -0
- data/lib/HDLRuby/hdr_samples/counter_bench.rb +83 -0
- data/lib/HDLRuby/hdr_samples/dff.rb +9 -0
- data/lib/HDLRuby/hdr_samples/dff_bench.rb +66 -0
- data/lib/HDLRuby/hdr_samples/dff_counter.rb +20 -0
- data/lib/HDLRuby/hdr_samples/include.rb +14 -0
- data/lib/HDLRuby/hdr_samples/instance_open.rb +23 -0
- data/lib/HDLRuby/hdr_samples/mei8.rb +256 -0
- data/lib/HDLRuby/hdr_samples/mei8_bench.rb +309 -0
- data/lib/HDLRuby/hdr_samples/multer_gen.rb +8 -0
- data/lib/HDLRuby/hdr_samples/multer_seq.rb +29 -0
- data/lib/HDLRuby/hdr_samples/neural/a.rb +9 -0
- data/lib/HDLRuby/hdr_samples/neural/a_sub.rb +5 -0
- data/lib/HDLRuby/hdr_samples/neural/bw.rb +23 -0
- data/lib/HDLRuby/hdr_samples/neural/counter.rb +16 -0
- data/lib/HDLRuby/hdr_samples/neural/dadz.rb +9 -0
- data/lib/HDLRuby/hdr_samples/neural/dadz_sub.rb +4 -0
- data/lib/HDLRuby/hdr_samples/neural/forward.rb +153 -0
- data/lib/HDLRuby/hdr_samples/neural/forward_sub.rb +62 -0
- data/lib/HDLRuby/hdr_samples/neural/forward_sub_rand.rb +41 -0
- data/lib/HDLRuby/hdr_samples/neural/forward_sub_rand_typedef.rb +47 -0
- data/lib/HDLRuby/hdr_samples/neural/mem.rb +30 -0
- data/lib/HDLRuby/hdr_samples/neural/random.rb +23 -0
- data/lib/HDLRuby/hdr_samples/neural/selector.rb +29 -0
- data/lib/HDLRuby/hdr_samples/neural/sigmoid.rb +20 -0
- data/lib/HDLRuby/hdr_samples/neural/z.rb +33 -0
- data/lib/HDLRuby/hdr_samples/prog.obj +256 -0
- data/lib/HDLRuby/hdr_samples/ram.rb +18 -0
- data/lib/HDLRuby/hdr_samples/register_with_code_bench.rb +98 -0
- data/lib/HDLRuby/hdr_samples/rom.rb +10 -0
- data/lib/HDLRuby/hdr_samples/struct.rb +14 -0
- data/lib/HDLRuby/hdr_samples/sumprod.rb +29 -0
- data/lib/HDLRuby/hdr_samples/sw_encrypt_bench.rb +103 -0
- data/lib/HDLRuby/hdr_samples/sw_encrypt_cpu_bench.rb +261 -0
- data/lib/HDLRuby/hdr_samples/sw_encrypt_cpusim_bench.rb +302 -0
- data/lib/HDLRuby/hdr_samples/system_open.rb +11 -0
- data/lib/HDLRuby/hdr_samples/tuple.rb +16 -0
- data/lib/HDLRuby/hdr_samples/with_channel.rb +118 -0
- data/lib/HDLRuby/hdr_samples/with_class.rb +199 -0
- data/lib/HDLRuby/hdr_samples/with_decoder.rb +17 -0
- data/lib/HDLRuby/hdr_samples/with_fsm.rb +34 -0
- data/lib/HDLRuby/hdr_samples/with_reconf.rb +103 -0
- data/lib/HDLRuby/hdrcc.rb +623 -0
- data/lib/HDLRuby/high_samples/_adder_fault.rb +23 -0
- data/lib/HDLRuby/high_samples/_generic_transmission2.rb +146 -0
- data/lib/HDLRuby/high_samples/adder.rb +21 -0
- data/lib/HDLRuby/high_samples/adder_common_errors.rb +25 -0
- data/lib/HDLRuby/high_samples/addsub.rb +33 -0
- data/lib/HDLRuby/high_samples/addsubz.rb +37 -0
- data/lib/HDLRuby/high_samples/after.rb +28 -0
- data/lib/HDLRuby/high_samples/all_signals.rb +29 -0
- data/lib/HDLRuby/high_samples/alu.rb +61 -0
- data/lib/HDLRuby/high_samples/anonymous.rb +41 -0
- data/lib/HDLRuby/high_samples/before.rb +28 -0
- data/lib/HDLRuby/high_samples/blockblock.rb +26 -0
- data/lib/HDLRuby/high_samples/bugs/dadz.rb +22 -0
- data/lib/HDLRuby/high_samples/bugs/misample_instan.rb +20 -0
- data/lib/HDLRuby/high_samples/bugs/misample_updown.rb +22 -0
- data/lib/HDLRuby/high_samples/bugs/sample_add.rb +16 -0
- data/lib/HDLRuby/high_samples/bugs/sample_barrel.rb +13 -0
- data/lib/HDLRuby/high_samples/bugs/sample_daice.rb +57 -0
- data/lib/HDLRuby/high_samples/bugs/sample_kumiawase.rb +52 -0
- data/lib/HDLRuby/high_samples/bugs/sample_multi.rb +18 -0
- data/lib/HDLRuby/high_samples/bugs/sample_sub.rb +14 -0
- data/lib/HDLRuby/high_samples/bugs/z2.rb +32 -0
- data/lib/HDLRuby/high_samples/case.rb +32 -0
- data/lib/HDLRuby/high_samples/case2.rb +30 -0
- data/lib/HDLRuby/high_samples/change.rb +23 -0
- data/lib/HDLRuby/high_samples/clocks.rb +35 -0
- data/lib/HDLRuby/high_samples/comparer.rb +21 -0
- data/lib/HDLRuby/high_samples/conditionals.rb +29 -0
- data/lib/HDLRuby/high_samples/dff.rb +23 -0
- data/lib/HDLRuby/high_samples/each.rb +28 -0
- data/lib/HDLRuby/high_samples/exporter.rb +42 -0
- data/lib/HDLRuby/high_samples/functions.rb +60 -0
- data/lib/HDLRuby/high_samples/if_seq.rb +26 -0
- data/lib/HDLRuby/high_samples/inherit_as_dff.rb +32 -0
- data/lib/HDLRuby/high_samples/inherit_dff.rb +36 -0
- data/lib/HDLRuby/high_samples/instance.rb +37 -0
- data/lib/HDLRuby/high_samples/memory.rb +64 -0
- data/lib/HDLRuby/high_samples/multi_file.rb +27 -0
- data/lib/HDLRuby/high_samples/overload.rb +32 -0
- data/lib/HDLRuby/high_samples/paper_after.rb +49 -0
- data/lib/HDLRuby/high_samples/ram.rb +27 -0
- data/lib/HDLRuby/high_samples/registers.rb +139 -0
- data/lib/HDLRuby/high_samples/rom.rb +23 -0
- data/lib/HDLRuby/high_samples/scopeblockname.rb +37 -0
- data/lib/HDLRuby/high_samples/scopescope.rb +26 -0
- data/lib/HDLRuby/high_samples/shift.rb +31 -0
- data/lib/HDLRuby/high_samples/shift2.rb +40 -0
- data/lib/HDLRuby/high_samples/simple_instance.rb +31 -0
- data/lib/HDLRuby/high_samples/test_all.sh +10 -0
- data/lib/HDLRuby/high_samples/typedef.rb +24 -0
- data/lib/HDLRuby/high_samples/values.rb +70 -0
- data/lib/HDLRuby/high_samples/vector.rb +22 -0
- data/lib/HDLRuby/high_samples/with_decoder.rb +30 -0
- data/lib/HDLRuby/high_samples/with_fsm.rb +46 -0
- data/lib/HDLRuby/high_samples/with_pipe.rb +43 -0
- data/lib/HDLRuby/high_samples/with_seq.rb +25 -0
- data/lib/HDLRuby/hruby_bstr.rb +1085 -0
- data/lib/HDLRuby/hruby_check.rb +317 -0
- data/lib/HDLRuby/hruby_db.rb +432 -0
- data/lib/HDLRuby/hruby_error.rb +44 -0
- data/lib/HDLRuby/hruby_high.rb +4103 -0
- data/lib/HDLRuby/hruby_low.rb +4735 -0
- data/lib/HDLRuby/hruby_low2c.rb +1986 -0
- data/lib/HDLRuby/hruby_low2high.rb +738 -0
- data/lib/HDLRuby/hruby_low2seq.rb +248 -0
- data/lib/HDLRuby/hruby_low2sym.rb +126 -0
- data/lib/HDLRuby/hruby_low2vhd.rb +1437 -0
- data/lib/HDLRuby/hruby_low_bool2select.rb +295 -0
- data/lib/HDLRuby/hruby_low_cleanup.rb +193 -0
- data/lib/HDLRuby/hruby_low_fix_types.rb +437 -0
- data/lib/HDLRuby/hruby_low_mutable.rb +1803 -0
- data/lib/HDLRuby/hruby_low_resolve.rb +165 -0
- data/lib/HDLRuby/hruby_low_skeleton.rb +129 -0
- data/lib/HDLRuby/hruby_low_with_bool.rb +141 -0
- data/lib/HDLRuby/hruby_low_with_port.rb +167 -0
- data/lib/HDLRuby/hruby_low_with_var.rb +302 -0
- data/lib/HDLRuby/hruby_low_without_bit2vector.rb +88 -0
- data/lib/HDLRuby/hruby_low_without_concat.rb +162 -0
- data/lib/HDLRuby/hruby_low_without_connection.rb +113 -0
- data/lib/HDLRuby/hruby_low_without_namespace.rb +718 -0
- data/lib/HDLRuby/hruby_low_without_outread.rb +107 -0
- data/lib/HDLRuby/hruby_low_without_select.rb +206 -0
- data/lib/HDLRuby/hruby_serializer.rb +398 -0
- data/lib/HDLRuby/hruby_tools.rb +37 -0
- data/lib/HDLRuby/hruby_types.rb +239 -0
- data/lib/HDLRuby/hruby_values.rb +64 -0
- data/lib/HDLRuby/hruby_verilog.rb +1888 -0
- data/lib/HDLRuby/hruby_verilog_name.rb +52 -0
- data/lib/HDLRuby/low_samples/adder.yaml +97 -0
- data/lib/HDLRuby/low_samples/after.yaml +228 -0
- data/lib/HDLRuby/low_samples/before.yaml +223 -0
- data/lib/HDLRuby/low_samples/blockblock.yaml +48 -0
- data/lib/HDLRuby/low_samples/bugs/sample_add.yaml +97 -0
- data/lib/HDLRuby/low_samples/bugs/sample_daice.yaml +444 -0
- data/lib/HDLRuby/low_samples/bugs/sample_kumiawase.yaml +332 -0
- data/lib/HDLRuby/low_samples/bugs/sample_sub.yaml +97 -0
- data/lib/HDLRuby/low_samples/bugs/seqpar.yaml +184 -0
- data/lib/HDLRuby/low_samples/case.yaml +327 -0
- data/lib/HDLRuby/low_samples/change.yaml +135 -0
- data/lib/HDLRuby/low_samples/clocks.yaml +674 -0
- data/lib/HDLRuby/low_samples/cloner.rb +22 -0
- data/lib/HDLRuby/low_samples/comparer.yaml +85 -0
- data/lib/HDLRuby/low_samples/conditionals.yaml +133 -0
- data/lib/HDLRuby/low_samples/dff.yaml +107 -0
- data/lib/HDLRuby/low_samples/each.yaml +1328 -0
- data/lib/HDLRuby/low_samples/exporter.yaml +226 -0
- data/lib/HDLRuby/low_samples/functions.yaml +298 -0
- data/lib/HDLRuby/low_samples/generic_transmission.yaml +597 -0
- data/lib/HDLRuby/low_samples/inherit_as_dff.yaml +125 -0
- data/lib/HDLRuby/low_samples/inherit_dff.yaml +107 -0
- data/lib/HDLRuby/low_samples/load_yaml.rb +11 -0
- data/lib/HDLRuby/low_samples/memory.yaml +678 -0
- data/lib/HDLRuby/low_samples/namespace_extractor.rb +23 -0
- data/lib/HDLRuby/low_samples/overload.yaml +226 -0
- data/lib/HDLRuby/low_samples/paper_after.yaml +431 -0
- data/lib/HDLRuby/low_samples/port_maker.rb +14 -0
- data/lib/HDLRuby/low_samples/ram.yaml +207 -0
- data/lib/HDLRuby/low_samples/registers.yaml +228 -0
- data/lib/HDLRuby/low_samples/rom.yaml +2950 -0
- data/lib/HDLRuby/low_samples/shift.yaml +230 -0
- data/lib/HDLRuby/low_samples/shift2.yaml +2095 -0
- data/lib/HDLRuby/low_samples/simple_instance.yaml +102 -0
- data/lib/HDLRuby/low_samples/test_all.sh +43 -0
- data/lib/HDLRuby/low_samples/typedef.yaml +115 -0
- data/lib/HDLRuby/low_samples/values.yaml +577 -0
- data/lib/HDLRuby/low_samples/variable_maker.rb +14 -0
- data/lib/HDLRuby/low_samples/vector.yaml +56 -0
- data/lib/HDLRuby/low_samples/with_seq.yaml +188 -0
- data/lib/HDLRuby/low_samples/yaml2hdr.rb +10 -0
- data/lib/HDLRuby/low_samples/yaml2vhd.rb +19 -0
- data/lib/HDLRuby/sim/Makefile +19 -0
- data/lib/HDLRuby/sim/hruby_sim.h +590 -0
- data/lib/HDLRuby/sim/hruby_sim_calc.c +2362 -0
- data/lib/HDLRuby/sim/hruby_sim_core.c +589 -0
- data/lib/HDLRuby/sim/hruby_sim_list.c +93 -0
- data/lib/HDLRuby/sim/hruby_sim_vizualize.c +91 -0
- data/lib/HDLRuby/sim/hruby_value_pool.c +64 -0
- data/lib/HDLRuby/std/channel.rb +354 -0
- data/lib/HDLRuby/std/clocks.rb +165 -0
- data/lib/HDLRuby/std/counters.rb +82 -0
- data/lib/HDLRuby/std/decoder.rb +214 -0
- data/lib/HDLRuby/std/fsm.rb +516 -0
- data/lib/HDLRuby/std/pipeline.rb +220 -0
- data/lib/HDLRuby/std/reconf.rb +309 -0
- data/lib/HDLRuby/test_hruby_bstr.rb +2259 -0
- data/lib/HDLRuby/test_hruby_high.rb +594 -0
- data/lib/HDLRuby/test_hruby_high_low.rb +99 -0
- data/lib/HDLRuby/test_hruby_low.rb +934 -0
- data/lib/HDLRuby/v_samples/adder.v +10 -0
- data/lib/HDLRuby/v_samples/dff.v +12 -0
- data/lib/HDLRuby/v_samples/ram.v +20 -0
- data/lib/HDLRuby/v_samples/rom.v +270 -0
- data/lib/HDLRuby/version.rb +3 -0
- data/lib/HDLRuby.rb +11 -0
- data/makedoc +1 -0
- data/metadata.yaml +4 -0
- metadata +299 -0
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
#include <limits.h>
|
|
5
|
+
#include <pthread.h>
|
|
6
|
+
|
|
7
|
+
#include "hruby_sim.h"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The HDLRuby simulation core, to be used with C code generated by
|
|
12
|
+
* hruby_low2c.
|
|
13
|
+
* */
|
|
14
|
+
|
|
15
|
+
/** The number of all the signals. */
|
|
16
|
+
static int num_all_signals = 0;
|
|
17
|
+
/** The capacity of the set of signals. */
|
|
18
|
+
static int cap_all_signals = 0;
|
|
19
|
+
/** The set of all the signals. */
|
|
20
|
+
static SignalI* all_signals = NULL;
|
|
21
|
+
|
|
22
|
+
/** The list of touched signals. */
|
|
23
|
+
static ListS touched_signals_content = { NULL, NULL };
|
|
24
|
+
static List touched_signals = &touched_signals_content;
|
|
25
|
+
|
|
26
|
+
/** The list of touched signals in the sequential execution model. */
|
|
27
|
+
static ListS touched_signals_seq_content = { NULL, NULL };
|
|
28
|
+
static List touched_signals_seq = &touched_signals_seq_content;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/** The list of activated code. */
|
|
32
|
+
static ListS activate_codes_content = { NULL, NULL };
|
|
33
|
+
static List activate_codes = &activate_codes_content;
|
|
34
|
+
|
|
35
|
+
/** The number of timed behaviors. */
|
|
36
|
+
static int num_timed_behaviors = 0;
|
|
37
|
+
/** The capacity of the timed behaviors. */
|
|
38
|
+
static int cap_timed_behaviors = 0;
|
|
39
|
+
/** The timed behaviors. */
|
|
40
|
+
static Behavior* timed_behaviors = NULL;
|
|
41
|
+
|
|
42
|
+
/** The number of running behaviors. */
|
|
43
|
+
static int num_run_behaviors = 0;
|
|
44
|
+
/** The number of activated behaviors. */
|
|
45
|
+
static int num_active_behaviors = 0;
|
|
46
|
+
|
|
47
|
+
/** Flag saying the behaviors can run. */
|
|
48
|
+
static int behaviors_can_run = 0;
|
|
49
|
+
|
|
50
|
+
/** The current simulation time. */
|
|
51
|
+
static unsigned long long hruby_sim_time = 0;
|
|
52
|
+
|
|
53
|
+
/** The mutex for accessing the simulator ressources. */
|
|
54
|
+
static pthread_mutex_t hruby_sim_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
55
|
+
|
|
56
|
+
/** The condition the behaviors wait on. */
|
|
57
|
+
static pthread_cond_t hruby_beh_cond = PTHREAD_COND_INITIALIZER;
|
|
58
|
+
/** The condition the simulator waits on. */
|
|
59
|
+
static pthread_cond_t hruby_sim_cond = PTHREAD_COND_INITIALIZER;
|
|
60
|
+
|
|
61
|
+
/** Flags for the simulation. */
|
|
62
|
+
static int sim_end_flag = 0;
|
|
63
|
+
|
|
64
|
+
/** Adds a timed behavior for processing.
|
|
65
|
+
* @param behavior the timed behavior to register */
|
|
66
|
+
void register_timed_behavior(Behavior behavior) {
|
|
67
|
+
if (num_timed_behaviors == cap_timed_behaviors) {
|
|
68
|
+
if (cap_timed_behaviors == 0) {
|
|
69
|
+
/* Need to create the array containing the timed behaviors. */
|
|
70
|
+
cap_timed_behaviors = 5;
|
|
71
|
+
timed_behaviors = calloc(sizeof(Behavior),cap_timed_behaviors);
|
|
72
|
+
} else {
|
|
73
|
+
/* Need to increase the capacity. */
|
|
74
|
+
Behavior* behaviors = calloc(sizeof(Behavior),cap_timed_behaviors*2);
|
|
75
|
+
memcpy(timed_behaviors,behaviors,sizeof(Behavior)*cap_timed_behaviors);
|
|
76
|
+
cap_timed_behaviors *= 2;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/* Add the behavior. */
|
|
80
|
+
timed_behaviors[num_timed_behaviors++] = behavior;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
/** Adds a signal for global processing.
|
|
85
|
+
* @param signal the signal to register */
|
|
86
|
+
void register_signal(SignalI signal) {
|
|
87
|
+
if (num_all_signals == cap_all_signals) {
|
|
88
|
+
if (cap_all_signals == 0) {
|
|
89
|
+
/* Need to create the array containing the timed behaviors. */
|
|
90
|
+
cap_all_signals = 100;
|
|
91
|
+
all_signals = calloc(sizeof(SignalI),cap_all_signals);
|
|
92
|
+
} else {
|
|
93
|
+
/* Need to increase the capacity. */
|
|
94
|
+
Behavior* behaviors = calloc(sizeof(Behavior),cap_all_signals*2);
|
|
95
|
+
memcpy(all_signals,behaviors,sizeof(Behavior)*cap_all_signals);
|
|
96
|
+
cap_all_signals *= 2;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/* Add the behavior. */
|
|
100
|
+
all_signals[num_all_signals++] = signal;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/** Recursively update the signals until no (untimed) behavior are
|
|
105
|
+
* activated. */
|
|
106
|
+
void hruby_sim_update_signals() {
|
|
107
|
+
// printf("hruby_sim_update_signals...\n");
|
|
108
|
+
/* As long as the list of touched signals is not empty go on computing. */
|
|
109
|
+
while(!empty_list(touched_signals) || !empty_list(touched_signals_seq)) {
|
|
110
|
+
// printf("## Checking touched signals.\n");
|
|
111
|
+
/* Sets the new signals values and mark the signals as activating. */
|
|
112
|
+
/* For the case of the parallel execution model. */
|
|
113
|
+
while(!empty_list(touched_signals)) {
|
|
114
|
+
Elem e = remove_list(touched_signals);
|
|
115
|
+
SignalI sig = e->data;
|
|
116
|
+
delete_element(e);
|
|
117
|
+
/* Is there a change? */
|
|
118
|
+
if (same_content_value(sig->c_value,sig->f_value)) continue;
|
|
119
|
+
/* Yes, process the signal. */
|
|
120
|
+
println_signal(sig);
|
|
121
|
+
// printf("c_value="); print_value(sig->c_value);
|
|
122
|
+
// printf("\nf_value="); print_value(sig->f_value); printf("\n");
|
|
123
|
+
// printf("Touched signal: %p (%s)\n",sig,sig->name);
|
|
124
|
+
/* Update the current value of the signal. */
|
|
125
|
+
copy_value(sig->f_value,sig->c_value);
|
|
126
|
+
// /* Mark the signal as activated. */
|
|
127
|
+
// add_list(activate_signals,e);
|
|
128
|
+
/* Mark the corresponding code as activated. */
|
|
129
|
+
/* Any edge activation. */
|
|
130
|
+
int i;
|
|
131
|
+
for(i=0; i<sig->num_any; ++i) {
|
|
132
|
+
Object obj = sig->any[i];
|
|
133
|
+
if (obj->kind == BEHAVIOR) {
|
|
134
|
+
/* Behavior case. */
|
|
135
|
+
Behavior beh = (Behavior)obj;
|
|
136
|
+
beh->activated = 1;
|
|
137
|
+
add_list(activate_codes,get_element(beh));
|
|
138
|
+
} else {
|
|
139
|
+
/* Other code case. */
|
|
140
|
+
Code cod = (Code)obj;
|
|
141
|
+
cod->activated = 1;
|
|
142
|
+
add_list(activate_codes,get_element(cod));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/* Positive edge activation. */
|
|
146
|
+
if (!zero_value(sig->c_value)) {
|
|
147
|
+
for(i=0; i<sig->num_pos; ++i) {
|
|
148
|
+
Object obj = sig->pos[i];
|
|
149
|
+
if (obj->kind == BEHAVIOR) {
|
|
150
|
+
/* Behavior case. */
|
|
151
|
+
Behavior beh = (Behavior)obj;
|
|
152
|
+
beh->activated = 1;
|
|
153
|
+
add_list(activate_codes,get_element(beh));
|
|
154
|
+
} else {
|
|
155
|
+
/* Other code case. */
|
|
156
|
+
Code cod = (Code)obj;
|
|
157
|
+
cod->activated = 1;
|
|
158
|
+
add_list(activate_codes,get_element(cod));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/* Negative edge activation. */
|
|
163
|
+
if (zero_value(sig->c_value)) {
|
|
164
|
+
for(i=0; i<sig->num_neg; ++i) {
|
|
165
|
+
Object obj = sig->neg[i];
|
|
166
|
+
if (obj->kind == BEHAVIOR) {
|
|
167
|
+
/* Behavior case. */
|
|
168
|
+
Behavior beh = (Behavior)obj;
|
|
169
|
+
beh->activated = 1;
|
|
170
|
+
add_list(activate_codes,get_element(beh));
|
|
171
|
+
} else {
|
|
172
|
+
/* Other code case. */
|
|
173
|
+
Code cod = (Code)obj;
|
|
174
|
+
cod->activated = 1;
|
|
175
|
+
add_list(activate_codes,get_element(cod));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/* And fdor the case of the sequential execution model
|
|
181
|
+
* (no more content check nor update of current value necessary). */
|
|
182
|
+
while(!empty_list(touched_signals_seq)) {
|
|
183
|
+
Elem e = remove_list(touched_signals_seq);
|
|
184
|
+
SignalI sig = e->data;
|
|
185
|
+
delete_element(e);
|
|
186
|
+
/* Yes, process the signal. */
|
|
187
|
+
println_signal(sig);
|
|
188
|
+
/* Update the current value of the signal. */
|
|
189
|
+
/* Mark the corresponding code as activated. */
|
|
190
|
+
/* Any edge activation. */
|
|
191
|
+
int i;
|
|
192
|
+
for(i=0; i<sig->num_any; ++i) {
|
|
193
|
+
Object obj = sig->any[i];
|
|
194
|
+
if (obj->kind == BEHAVIOR) {
|
|
195
|
+
/* Behavior case. */
|
|
196
|
+
Behavior beh = (Behavior)obj;
|
|
197
|
+
beh->activated = 1;
|
|
198
|
+
add_list(activate_codes,get_element(beh));
|
|
199
|
+
} else {
|
|
200
|
+
/* Other code case. */
|
|
201
|
+
Code cod = (Code)obj;
|
|
202
|
+
cod->activated = 1;
|
|
203
|
+
add_list(activate_codes,get_element(cod));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/* Positive edge activation. */
|
|
207
|
+
if (!zero_value(sig->c_value)) {
|
|
208
|
+
for(i=0; i<sig->num_pos; ++i) {
|
|
209
|
+
Object obj = sig->pos[i];
|
|
210
|
+
if (obj->kind == BEHAVIOR) {
|
|
211
|
+
/* Behavior case. */
|
|
212
|
+
Behavior beh = (Behavior)obj;
|
|
213
|
+
beh->activated = 1;
|
|
214
|
+
add_list(activate_codes,get_element(beh));
|
|
215
|
+
} else {
|
|
216
|
+
/* Other code case. */
|
|
217
|
+
Code cod = (Code)obj;
|
|
218
|
+
cod->activated = 1;
|
|
219
|
+
add_list(activate_codes,get_element(cod));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/* Negative edge activation. */
|
|
224
|
+
if (zero_value(sig->c_value)) {
|
|
225
|
+
for(i=0; i<sig->num_neg; ++i) {
|
|
226
|
+
Object obj = sig->neg[i];
|
|
227
|
+
if (obj->kind == BEHAVIOR) {
|
|
228
|
+
/* Behavior case. */
|
|
229
|
+
Behavior beh = (Behavior)obj;
|
|
230
|
+
beh->activated = 1;
|
|
231
|
+
add_list(activate_codes,get_element(beh));
|
|
232
|
+
} else {
|
|
233
|
+
/* Other code case. */
|
|
234
|
+
Code cod = (Code)obj;
|
|
235
|
+
cod->activated = 1;
|
|
236
|
+
add_list(activate_codes,get_element(cod));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// printf("## Checking activate codes.\n");
|
|
243
|
+
/* Execute the behaviors activated by the signals. */
|
|
244
|
+
while(!empty_list(activate_codes)) {
|
|
245
|
+
Elem e = remove_list(activate_codes);
|
|
246
|
+
Object obj = e->data;
|
|
247
|
+
delete_element(e);
|
|
248
|
+
if (obj->kind == BEHAVIOR) {
|
|
249
|
+
/* Behavior case. */
|
|
250
|
+
Behavior beh = (Behavior)obj;
|
|
251
|
+
/* Is the code really activated? */
|
|
252
|
+
if (beh->activated) {
|
|
253
|
+
/* Yes, execute it. */
|
|
254
|
+
beh->block->function();
|
|
255
|
+
/* And deactivate it. */
|
|
256
|
+
beh->activated = 0;
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
/* Other code case. */
|
|
260
|
+
Code cod = (Code)obj;
|
|
261
|
+
/* Is the code really activated? */
|
|
262
|
+
if (cod->activated) {
|
|
263
|
+
/* Yes, execute it. */
|
|
264
|
+
cod->function();
|
|
265
|
+
/* And deactivate it. */
|
|
266
|
+
cod->activated = 0;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
/** Advance time to the next time step. */
|
|
275
|
+
void hruby_sim_advance_time() {
|
|
276
|
+
/* Collects the activation time of all the timed behaviors and find
|
|
277
|
+
* the shortest one. */
|
|
278
|
+
unsigned long long next_time = ULLONG_MAX;
|
|
279
|
+
int i;
|
|
280
|
+
for(i=0; i<num_timed_behaviors; ++i) {
|
|
281
|
+
unsigned long long beh_time = timed_behaviors[i]->active_time;
|
|
282
|
+
if (beh_time < next_time) next_time = beh_time;
|
|
283
|
+
}
|
|
284
|
+
/* Sets the new activation time. */
|
|
285
|
+
hruby_sim_time = next_time;
|
|
286
|
+
println_time(hruby_sim_time);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
/** Activates a behavior.
|
|
291
|
+
* @param behavior the behavior to activate. */
|
|
292
|
+
void activate_behavior(Behavior behavior) {
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
/** Activates the timed behavior that have to be activated at this
|
|
298
|
+
* time. */
|
|
299
|
+
void hruby_sim_activate_behaviors_on_time() {
|
|
300
|
+
int i;
|
|
301
|
+
// printf("$1\n");
|
|
302
|
+
pthread_mutex_lock(&hruby_sim_mutex);
|
|
303
|
+
/* Count the number of behaviors that will be activated. */
|
|
304
|
+
for(i=0; i<num_timed_behaviors; ++i) {
|
|
305
|
+
Behavior beh = timed_behaviors[i];
|
|
306
|
+
if (beh->active_time == hruby_sim_time) {
|
|
307
|
+
/* Increase the number of timed behavior to wait for. */
|
|
308
|
+
num_active_behaviors ++;
|
|
309
|
+
// printf("num_active_behaviors = %d\n",num_active_behaviors);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/* Activate the behaviors .*/
|
|
313
|
+
behaviors_can_run = 1;
|
|
314
|
+
// pthread_cond_signal(&compute_cond); /* No behaviors. */
|
|
315
|
+
pthread_cond_signal(&hruby_beh_cond);
|
|
316
|
+
pthread_mutex_unlock(&hruby_sim_mutex);
|
|
317
|
+
// printf("$2\n");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
/** Wait for the active timed behaviors to advance. */
|
|
322
|
+
void hruby_sim_wait_behaviors() {
|
|
323
|
+
// printf("$3\n");
|
|
324
|
+
pthread_mutex_lock(&hruby_sim_mutex);
|
|
325
|
+
while(num_active_behaviors > 0) {
|
|
326
|
+
// printf("num_active_behaviors = %d\n",num_active_behaviors);
|
|
327
|
+
// pthread_cond_wait(&active_behaviors_cond, &hruby_sim_mutex);
|
|
328
|
+
pthread_cond_wait(&hruby_sim_cond, &hruby_sim_mutex);
|
|
329
|
+
}
|
|
330
|
+
behaviors_can_run = 0;
|
|
331
|
+
pthread_mutex_unlock(&hruby_sim_mutex);
|
|
332
|
+
// printf("$4\n");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
/** The code for starting a behavior.
|
|
337
|
+
* @param arg the behavior to execute. */
|
|
338
|
+
void* behavior_run(void* arg) {
|
|
339
|
+
Behavior behavior = (Behavior)arg;
|
|
340
|
+
/* First lock the behavior until the simulation engine starts. */
|
|
341
|
+
// printf("#1\n");
|
|
342
|
+
pthread_mutex_lock(&hruby_sim_mutex);
|
|
343
|
+
num_active_behaviors -= 1;
|
|
344
|
+
while(!behaviors_can_run) {
|
|
345
|
+
// pthread_cond_wait(&compute_cond, &hruby_sim_mutex);
|
|
346
|
+
pthread_cond_wait(&hruby_beh_cond, &hruby_sim_mutex);
|
|
347
|
+
}
|
|
348
|
+
pthread_mutex_unlock(&hruby_sim_mutex);
|
|
349
|
+
// printf("#2\n");
|
|
350
|
+
/* Now can start the execution of the behavior. */
|
|
351
|
+
behavior->block->function();
|
|
352
|
+
/* Stops the behavior. */
|
|
353
|
+
pthread_mutex_lock(&hruby_sim_mutex);
|
|
354
|
+
num_active_behaviors -= 1;
|
|
355
|
+
num_run_behaviors -= 1;
|
|
356
|
+
pthread_cond_signal(&hruby_sim_cond);
|
|
357
|
+
pthread_mutex_unlock(&hruby_sim_mutex);
|
|
358
|
+
/* End the thread. */
|
|
359
|
+
pthread_exit(NULL);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
/** Starts the timed behaviors.
|
|
364
|
+
* @note create a thread per timed behavior. */
|
|
365
|
+
void hruby_sim_start_timed_behaviors() {
|
|
366
|
+
int i;
|
|
367
|
+
/* Sets the end flags to 0. */
|
|
368
|
+
sim_end_flag = 0;
|
|
369
|
+
/* Create and start the threads. */
|
|
370
|
+
for(i=0; i<num_timed_behaviors; ++i) {
|
|
371
|
+
num_run_behaviors += 1;
|
|
372
|
+
// ++num_active_behaviors;
|
|
373
|
+
// printf("0 num_active_behaviors = %d\n",num_active_behaviors);
|
|
374
|
+
pthread_create(&timed_behaviors[i]->thread,NULL,
|
|
375
|
+
&behavior_run,timed_behaviors[i]);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** Ends waiting all the threads properly terminates. */
|
|
380
|
+
void hruby_sim_end_timed_behaviors() {
|
|
381
|
+
int i;
|
|
382
|
+
/* Sets the end flag to 1. */
|
|
383
|
+
sim_end_flag = 1;
|
|
384
|
+
/* Wait for the threads to terminate. */
|
|
385
|
+
for(i=0; i<num_timed_behaviors; ++i) {
|
|
386
|
+
pthread_join(timed_behaviors[i]->thread,NULL);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
/** The simulation core function.
|
|
394
|
+
* @param limit the time limit in fs. */
|
|
395
|
+
void hruby_sim_core(unsigned long long limit) {
|
|
396
|
+
/* Initialize the time to 0. */
|
|
397
|
+
hruby_sim_time = 0;
|
|
398
|
+
|
|
399
|
+
/* Start all the timed behaviors. */
|
|
400
|
+
hruby_sim_start_timed_behaviors();
|
|
401
|
+
// /* Activate the timed behavior that are on time. */
|
|
402
|
+
// hruby_sim_activate_behaviors_on_time();
|
|
403
|
+
|
|
404
|
+
/* Run while there are active behaviors and the time limit is not
|
|
405
|
+
* reached */
|
|
406
|
+
while(hruby_sim_time<limit) {
|
|
407
|
+
int i;
|
|
408
|
+
// printf("num_active_behaviors = %d\n",num_active_behaviors);
|
|
409
|
+
/* Wait for the active timed behaviors to perform their computations. */
|
|
410
|
+
hruby_sim_wait_behaviors();
|
|
411
|
+
/* Update the signal values (recursively executing blocks locked
|
|
412
|
+
* on the signals). */
|
|
413
|
+
hruby_sim_update_signals();
|
|
414
|
+
if (num_run_behaviors <= 0) break;
|
|
415
|
+
/* Advance time to next timestep. */
|
|
416
|
+
hruby_sim_advance_time();
|
|
417
|
+
|
|
418
|
+
/* Mark the signals as fading. */
|
|
419
|
+
for(i=0; i<num_all_signals; ++i) {
|
|
420
|
+
all_signals[i]->fading = 1;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* Activate the timed behavior that are on time. */
|
|
424
|
+
hruby_sim_activate_behaviors_on_time();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
/* ##################################################################### */
|
|
432
|
+
/* ## The interface for the HW description. ## */
|
|
433
|
+
/* ##################################################################### */
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
/** Makes the behavior wait for a given time.
|
|
439
|
+
* @param delay the delay to wait in fs.
|
|
440
|
+
* @param behavior the current behavior. */
|
|
441
|
+
void hw_wait(unsigned long long delay, Behavior behavior) {
|
|
442
|
+
// printf("!1\n");
|
|
443
|
+
/* Maybe the thread is to end immediatly. */
|
|
444
|
+
if (sim_end_flag)
|
|
445
|
+
pthread_exit(NULL);
|
|
446
|
+
/* No go on with the wait procedure. */
|
|
447
|
+
pthread_mutex_lock(&hruby_sim_mutex);
|
|
448
|
+
/* Indicate the behavior finished current execution. */
|
|
449
|
+
num_active_behaviors -= 1;
|
|
450
|
+
pthread_cond_signal(&hruby_sim_cond);
|
|
451
|
+
/* Update the behavior's time. */
|
|
452
|
+
behavior->active_time += delay;
|
|
453
|
+
pthread_mutex_unlock(&hruby_sim_mutex);
|
|
454
|
+
/* Wait for being reactivated. */
|
|
455
|
+
while(behavior->active_time > hruby_sim_time) {
|
|
456
|
+
pthread_mutex_lock(&hruby_sim_mutex);
|
|
457
|
+
while(!behaviors_can_run) {
|
|
458
|
+
// pthread_cond_wait(&compute_cond, &hruby_sim_mutex);
|
|
459
|
+
pthread_cond_wait(&hruby_beh_cond, &hruby_sim_mutex);
|
|
460
|
+
}
|
|
461
|
+
pthread_mutex_unlock(&hruby_sim_mutex);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
/** Touch a signal.
|
|
467
|
+
* @param signal the signal to touch */
|
|
468
|
+
void touch_signal(SignalI signal) {
|
|
469
|
+
// printf("touching signal: %p\n",signal);
|
|
470
|
+
add_list(touched_signals,get_element(signal));
|
|
471
|
+
// println_signal(signal);
|
|
472
|
+
/* Now the signal is not fading any longer. */
|
|
473
|
+
signal->fading = 0;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
/** Transmit a value to a signal.
|
|
478
|
+
* @param value the value to transmit
|
|
479
|
+
* @param signal the signal to transmit the value to. */
|
|
480
|
+
void transmit_to_signal(Value value, SignalI signal) {
|
|
481
|
+
// printf("Tansmit to signal: %s(%p) with fading=%d\n",signal->name,signal,signal->fading);
|
|
482
|
+
/* Copy the content. */
|
|
483
|
+
if (signal->fading)
|
|
484
|
+
signal->f_value = copy_value(value,signal->f_value);
|
|
485
|
+
else
|
|
486
|
+
signal->f_value = copy_value_no_z(value,signal->f_value);
|
|
487
|
+
/* And touch the signal. */
|
|
488
|
+
touch_signal(signal);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** Transmit a value to a range within a signal.
|
|
492
|
+
* @param value the value to transmit
|
|
493
|
+
* @param ref the reference to the range in the signal to transmit the
|
|
494
|
+
* value to. */
|
|
495
|
+
void transmit_to_signal_range(Value value, RefRangeS ref) {
|
|
496
|
+
SignalI signal = ref.signal;
|
|
497
|
+
unsigned long long first = ref.first;
|
|
498
|
+
unsigned long long last = ref.last;
|
|
499
|
+
// printf("Tansmit to signal range: %s(%p)\n",signal->name,signal);
|
|
500
|
+
/* Can transmit, copy the content. */
|
|
501
|
+
if (signal->fading)
|
|
502
|
+
signal->f_value = write_range(value,first,last,signal->f_value);
|
|
503
|
+
else
|
|
504
|
+
signal->f_value = write_range_no_z(value,first,last,signal->f_value);
|
|
505
|
+
/* And touch the signal. */
|
|
506
|
+
touch_signal(signal);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
/** Touch a signal in case of sequential execution model.
|
|
512
|
+
* @param signal the signal to touch */
|
|
513
|
+
void touch_signal_seq(SignalI signal) {
|
|
514
|
+
// printf("touching signal seq: %p\n",signal);
|
|
515
|
+
/* Is there a difference between the present and future value? */
|
|
516
|
+
if (same_content_value(signal->c_value,signal->f_value)) return;
|
|
517
|
+
/* Yes, add the signal to the list of touched sequential ones and update
|
|
518
|
+
* its current value. */
|
|
519
|
+
add_list(touched_signals_seq,get_element(signal));
|
|
520
|
+
copy_value(signal->f_value,signal->c_value);
|
|
521
|
+
// println_signal(signal);
|
|
522
|
+
/* Now the signal is not fading any longer. */
|
|
523
|
+
signal->fading = 0;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
/** Transmit a value to a signal in case of a sequential execution model.
|
|
528
|
+
* @param value the value to transmit
|
|
529
|
+
* @param signal the signal to transmit the value to. */
|
|
530
|
+
void transmit_to_signal_seq(Value value, SignalI signal) {
|
|
531
|
+
// printf("Tansmit to signal seq: %s(%p)\n",signal->name,signal);
|
|
532
|
+
/* Copy the content. */
|
|
533
|
+
if (signal->fading)
|
|
534
|
+
copy_value(value,signal->f_value);
|
|
535
|
+
else
|
|
536
|
+
copy_value_no_z(value,signal->f_value);
|
|
537
|
+
/* And touch the signal. */
|
|
538
|
+
touch_signal_seq(signal);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Transmit a value to a range within a signal in case of sequential
|
|
542
|
+
* execution model.
|
|
543
|
+
* @param value the value to transmit
|
|
544
|
+
* @param ref the reference to the range in the signal to transmit the
|
|
545
|
+
* value to. */
|
|
546
|
+
void transmit_to_signal_range_seq(Value value, RefRangeS ref) {
|
|
547
|
+
SignalI signal = ref.signal;
|
|
548
|
+
unsigned long long first = ref.first;
|
|
549
|
+
unsigned long long last = ref.last;
|
|
550
|
+
// printf("Tansmit to signal range: %s(%p)\n",signal->name,signal);
|
|
551
|
+
/* Can transmit, copy the content. */
|
|
552
|
+
if (signal->fading)
|
|
553
|
+
write_range(value,first,last,signal->f_value);
|
|
554
|
+
else
|
|
555
|
+
write_range_no_z(value,first,last,signal->f_value);
|
|
556
|
+
/* And touch the signal. */
|
|
557
|
+
touch_signal_seq(signal);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** Creates an event.
|
|
561
|
+
* @param edge the edge of the event
|
|
562
|
+
* @param signal the signal of the event */
|
|
563
|
+
Event make_event(Edge edge, SignalI signal) {
|
|
564
|
+
Event event = malloc(sizeof(EventS));
|
|
565
|
+
event->edge = edge;
|
|
566
|
+
event->signal = signal;
|
|
567
|
+
|
|
568
|
+
return event;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
/** Creates a delay.
|
|
573
|
+
* Actually generates an unsigned long long giving the corresponding
|
|
574
|
+
* delay in the base unit of the simulator.
|
|
575
|
+
* @param value the value of the delay
|
|
576
|
+
* @param unit the used unit
|
|
577
|
+
* @return the result delay in the base unit of the simulator (ns) */
|
|
578
|
+
unsigned long long make_delay(int value, Unit unit) {
|
|
579
|
+
switch(unit) {
|
|
580
|
+
case S: return value * 1000000000ULL;
|
|
581
|
+
case MS: return value * 1000000ULL;
|
|
582
|
+
case US: return value * 1000ULL;
|
|
583
|
+
case NS: return value * 1ULL;
|
|
584
|
+
default:
|
|
585
|
+
perror("Invalid unit for a delay.");
|
|
586
|
+
}
|
|
587
|
+
return -1;
|
|
588
|
+
}
|
|
589
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#include <stdlib.h>
|
|
2
|
+
|
|
3
|
+
#include "hruby_sim.h"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The lists used in HDLRuby simulation, to be used with C code generated by
|
|
7
|
+
* hruby_low2c.
|
|
8
|
+
* */
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/* The pool of list elements to reduce number of memory allocations. */
|
|
12
|
+
static ListS pool_elements = { NULL, NULL };
|
|
13
|
+
|
|
14
|
+
/** Get a list element for containing some data.
|
|
15
|
+
* @param data the data of the element
|
|
16
|
+
* @return the resulting element */
|
|
17
|
+
Elem get_element(void* data) {
|
|
18
|
+
Elem elem; /* The resulting element. */
|
|
19
|
+
/* Is the pool empty? */
|
|
20
|
+
if (empty_list(&pool_elements)) {
|
|
21
|
+
/* Yes, allocates a new element. */
|
|
22
|
+
elem = malloc(sizeof(ElemS));
|
|
23
|
+
elem->data = data;
|
|
24
|
+
elem->next = NULL;
|
|
25
|
+
} else {
|
|
26
|
+
/* No, get the element from the pool. */
|
|
27
|
+
elem = pool_elements.head;
|
|
28
|
+
elem->data = data;
|
|
29
|
+
elem->next = NULL;
|
|
30
|
+
pool_elements.head = pool_elements.head->next;
|
|
31
|
+
if (pool_elements.tail == elem)
|
|
32
|
+
pool_elements.tail = NULL;
|
|
33
|
+
}
|
|
34
|
+
return elem;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Delete an element (it will return to the pool).
|
|
38
|
+
* @param elem the element to delete */
|
|
39
|
+
void delete_element(Elem elem) {
|
|
40
|
+
elem->data = NULL;
|
|
41
|
+
add_list(&pool_elements,elem);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
/** Builds a list.
|
|
46
|
+
* @param list the place where to build the list
|
|
47
|
+
* @return the resulting list */
|
|
48
|
+
List build_list(List list) {
|
|
49
|
+
list->head = list->tail = NULL;
|
|
50
|
+
return list;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Clears a list.
|
|
54
|
+
* @param list the list to clear */
|
|
55
|
+
void clear_list(List list) {
|
|
56
|
+
list->head = list->tail = NULL;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Adds an element to the tail of a list.
|
|
60
|
+
* @param list the list to add the element in
|
|
61
|
+
* @param elem the element to add in the list */
|
|
62
|
+
void add_list(List list, Elem elem) {
|
|
63
|
+
/* Ensures the element is unlinked. */
|
|
64
|
+
elem->next = NULL;
|
|
65
|
+
/* Is the list empty? */
|
|
66
|
+
if (empty_list(list)) {
|
|
67
|
+
/* Yes, the element is the head and the tail. */
|
|
68
|
+
list->head = list->tail = elem;
|
|
69
|
+
} else {
|
|
70
|
+
/* No, simply add to the tail. */
|
|
71
|
+
list->tail->next = elem;
|
|
72
|
+
list->tail = elem;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Remove the head of the list.
|
|
77
|
+
* @param list the list to remove the head from
|
|
78
|
+
* @return the removed element */
|
|
79
|
+
Elem remove_list(List list) {
|
|
80
|
+
/* Is the list empty? */
|
|
81
|
+
if (empty_list(list)) {
|
|
82
|
+
/* Yes, no element to remove. */
|
|
83
|
+
return NULL;
|
|
84
|
+
} else {
|
|
85
|
+
/* No, remove the head. */
|
|
86
|
+
Elem elem = list->head;
|
|
87
|
+
list->head = list->head->next;
|
|
88
|
+
if (list->tail == elem) {
|
|
89
|
+
list->tail = NULL;
|
|
90
|
+
}
|
|
91
|
+
return elem;
|
|
92
|
+
}
|
|
93
|
+
}
|