HDLRuby 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|