redshift 1.3.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/.gitignore +8 -0
  2. data/README +5 -0
  3. data/RELEASE-NOTES +455 -0
  4. data/TODO +431 -0
  5. data/bench/alg-state.rb +61 -0
  6. data/bench/bench +26 -0
  7. data/bench/bench.rb +10 -0
  8. data/bench/continuous.rb +76 -0
  9. data/bench/diff-bench +86 -0
  10. data/bench/discrete.rb +101 -0
  11. data/bench/euler.rb +50 -0
  12. data/bench/formula.rb +78 -0
  13. data/bench/half-strict.rb +103 -0
  14. data/bench/inertness.rb +116 -0
  15. data/bench/queue.rb +92 -0
  16. data/bench/run +66 -0
  17. data/bench/simple.rb +74 -0
  18. data/bench/strictness.rb +86 -0
  19. data/examples/ball-tkar.rb +72 -0
  20. data/examples/ball.rb +123 -0
  21. data/examples/collide.rb +70 -0
  22. data/examples/connect-parallel.rb +48 -0
  23. data/examples/connect.rb +109 -0
  24. data/examples/constants.rb +27 -0
  25. data/examples/delay.rb +80 -0
  26. data/examples/derivative.rb +77 -0
  27. data/examples/euler.rb +46 -0
  28. data/examples/external-lib.rb +33 -0
  29. data/examples/guard-debugger.rb +77 -0
  30. data/examples/lotka-volterra.rb +33 -0
  31. data/examples/persist-ball.rb +68 -0
  32. data/examples/pid.rb +87 -0
  33. data/examples/ports.rb +60 -0
  34. data/examples/queue.rb +56 -0
  35. data/examples/queue2.rb +98 -0
  36. data/examples/reset-with-event-val.rb +28 -0
  37. data/examples/scheduler.rb +104 -0
  38. data/examples/set-dest.rb +23 -0
  39. data/examples/simulink/README +1 -0
  40. data/examples/simulink/delay.mdl +827 -0
  41. data/examples/simulink/derivative.mdl +655 -0
  42. data/examples/step-discrete-profiler.rb +103 -0
  43. data/examples/subsystem.rb +109 -0
  44. data/examples/sync-deadlock.rb +32 -0
  45. data/examples/sync-queue.rb +91 -0
  46. data/examples/sync-retry.rb +20 -0
  47. data/examples/sync.rb +51 -0
  48. data/examples/thermostat.rb +53 -0
  49. data/examples/zeno.rb +53 -0
  50. data/lib/accessible-index.rb +47 -0
  51. data/lib/redshift.rb +1 -0
  52. data/lib/redshift/component.rb +412 -0
  53. data/lib/redshift/meta.rb +183 -0
  54. data/lib/redshift/mixins/zeno-debugger.rb +69 -0
  55. data/lib/redshift/port.rb +57 -0
  56. data/lib/redshift/queue.rb +104 -0
  57. data/lib/redshift/redshift.rb +111 -0
  58. data/lib/redshift/state.rb +31 -0
  59. data/lib/redshift/syntax.rb +558 -0
  60. data/lib/redshift/target/c.rb +37 -0
  61. data/lib/redshift/target/c/component-gen.rb +1303 -0
  62. data/lib/redshift/target/c/flow-gen.rb +325 -0
  63. data/lib/redshift/target/c/flow/algebraic.rb +85 -0
  64. data/lib/redshift/target/c/flow/buffer.rb +74 -0
  65. data/lib/redshift/target/c/flow/delay.rb +203 -0
  66. data/lib/redshift/target/c/flow/derivative.rb +101 -0
  67. data/lib/redshift/target/c/flow/euler.rb +67 -0
  68. data/lib/redshift/target/c/flow/expr.rb +113 -0
  69. data/lib/redshift/target/c/flow/rk4.rb +80 -0
  70. data/lib/redshift/target/c/library.rb +85 -0
  71. data/lib/redshift/target/c/world-gen.rb +1370 -0
  72. data/lib/redshift/target/spec.rb +34 -0
  73. data/lib/redshift/world.rb +300 -0
  74. data/rakefile +37 -0
  75. data/test/test.rb +52 -0
  76. data/test/test_buffer.rb +58 -0
  77. data/test/test_connect.rb +242 -0
  78. data/test/test_connect_parallel.rb +47 -0
  79. data/test/test_connect_strict.rb +135 -0
  80. data/test/test_constant.rb +74 -0
  81. data/test/test_delay.rb +145 -0
  82. data/test/test_derivative.rb +48 -0
  83. data/test/test_discrete.rb +592 -0
  84. data/test/test_discrete_isolated.rb +92 -0
  85. data/test/test_exit.rb +59 -0
  86. data/test/test_flow.rb +200 -0
  87. data/test/test_flow_link.rb +288 -0
  88. data/test/test_flow_sub.rb +100 -0
  89. data/test/test_flow_trans.rb +292 -0
  90. data/test/test_inherit.rb +127 -0
  91. data/test/test_inherit_event.rb +74 -0
  92. data/test/test_inherit_flow.rb +139 -0
  93. data/test/test_inherit_link.rb +65 -0
  94. data/test/test_inherit_setup.rb +56 -0
  95. data/test/test_inherit_state.rb +66 -0
  96. data/test/test_inherit_transition.rb +168 -0
  97. data/test/test_numerics.rb +34 -0
  98. data/test/test_queue.rb +90 -0
  99. data/test/test_queue_alone.rb +115 -0
  100. data/test/test_reset.rb +209 -0
  101. data/test/test_setup.rb +119 -0
  102. data/test/test_strict_continuity.rb +410 -0
  103. data/test/test_strict_reset_error.rb +30 -0
  104. data/test/test_strictness_error.rb +32 -0
  105. data/test/test_sync.rb +185 -0
  106. data/test/test_world.rb +328 -0
  107. metadata +204 -0
@@ -0,0 +1,80 @@
1
+ module RedShift; class RK4DifferentialFlow
2
+ def flow_wrapper cl, state
3
+ var_name = @var
4
+ flow = self
5
+
6
+ flow_name = "flow_#{CGenerator.make_c_name cl.name}_#{var_name}_#{state}"
7
+
8
+ Component::FlowWrapper.make_subclass flow_name do
9
+ @inspect_str = "#{cl.name}:#{state}: #{var_name} = #{flow.formula}"
10
+
11
+ ssn = cl.shadow_struct.name
12
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
13
+
14
+ # We need the struct
15
+ shadow_library_source_file.include(cl.shadow_library_include_file)
16
+
17
+ shadow_library_source_file.define(flow_name).instance_eval do
18
+ arguments "ComponentShadow *comp_shdw"
19
+ declare :shadow => %{
20
+ struct #{ssn} *shadow;
21
+ struct #{cont_state_ssn} *cont_state;
22
+ ContVar *var;
23
+ double ddt_#{var_name};
24
+ double value_4;
25
+ double time_step;
26
+ }
27
+ setup :shadow => %{
28
+ shadow = (#{ssn} *)comp_shdw;
29
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
30
+ var = &cont_state->#{var_name};
31
+ time_step = shadow->world->time_step;
32
+ }
33
+ setup :rk_level => %{
34
+ shadow->world->rk_level--;
35
+ } # has to happen before referenced alg flows are called in other setups
36
+ body %{
37
+ switch (shadow->world->rk_level) {
38
+ case 0:
39
+ #{flow.translate(self, "ddt_#{var_name}", 0, cl).join("
40
+ ")};
41
+ var->value_1 = var->value_0 + ddt_#{var_name} * time_step/2;
42
+ break;
43
+
44
+ case 1:
45
+ #{flow.translate(self, "ddt_#{var_name}", 1, cl).join("
46
+ ")};
47
+ var->value_2 = var->value_0 + ddt_#{var_name} * time_step/2;
48
+ break;
49
+
50
+ case 2:
51
+ #{flow.translate(self, "ddt_#{var_name}", 2, cl).join("
52
+ ")};
53
+ var->value_3 = var->value_0 + ddt_#{var_name} * time_step;
54
+ break;
55
+
56
+ case 3:
57
+ #{flow.translate(self, "ddt_#{var_name}", 3, cl).join("
58
+ ")};
59
+ value_4 = var->value_0 + ddt_#{var_name} * time_step;
60
+ var->value_0 =
61
+ (-3*var->value_0 + 2*var->value_1 + 4*var->value_2 +
62
+ 2*var->value_3 + value_4) / 6;
63
+ break;
64
+
65
+ default:
66
+ rb_raise(#{declare_class RuntimeError},
67
+ "Bad rk_level, %d!", shadow->world->rk_level);
68
+ }
69
+
70
+ shadow->world->rk_level++;
71
+ var->rk_level = shadow->world->rk_level;
72
+ }
73
+ end
74
+
75
+ define_c_method :calc_function_pointer do
76
+ body "shadow->flow = &#{flow_name}"
77
+ end
78
+ end
79
+ end
80
+ end; end
@@ -0,0 +1,85 @@
1
+ $CGEN_VERBOSE = $REDSHIFT_CGEN_VERBOSE ## ugh.
2
+
3
+ require 'cgen/cshadow'
4
+
5
+ module RedShift
6
+ def RedShift.library
7
+ @clib ||= Library.new($REDSHIFT_CLIB_NAME)
8
+ end
9
+
10
+ class Library < CShadow::Library
11
+ def initialize(*args)
12
+ super
13
+
14
+ self.purge_source_dir = :delete
15
+ self.show_times_flag = $REDSHIFT_BUILD_TIMES
16
+
17
+ if $REDSHIFT_DEBUG
18
+ include_file.include "<assert.h>"
19
+ ## better to use something that raises a ruby exception
20
+ else
21
+ include_file.declare :assert => %{#define assert(cond) 0}
22
+ end
23
+
24
+ include_file.include '<math.h>'
25
+ end
26
+
27
+ # Call this to link with external libraries. See examples/external-lib.rb.
28
+ def link_with *libs
29
+ (@link_libs ||= []) << libs
30
+ end
31
+
32
+ def declare_external_constant *vars
33
+ @external_constants ||= {}
34
+ vars.each do |var|
35
+ @external_constants[var.to_s] = true
36
+ end
37
+ end
38
+
39
+ def external_constant? var
40
+ @external_constants and @external_constants.key?(var.to_s)
41
+ end
42
+
43
+ def extconf
44
+ super do |lines|
45
+ if @link_libs
46
+ libstr = " " + @link_libs.flatten.join(" ")
47
+ lines << %{$LOCAL_LIBS << "#{libstr}"}
48
+ end
49
+ end
50
+ end
51
+
52
+ def commit
53
+ return if committed?
54
+ precommit
55
+
56
+ ## this makes it a little trickier to use gdb
57
+ use_work_dir $REDSHIFT_WORK_DIR do
58
+ # $REDSHIFT_SKIP_BUILD is normally handled in redshift/target/c.rb.
59
+ # useful for: turnkey; fast start if no changes; manual lib edits
60
+ super(!$REDSHIFT_SKIP_BUILD)
61
+ end
62
+ ## freeze metadata in comp classes?
63
+ ## can cgen/cshadow freeze some stuff?
64
+ end
65
+
66
+ # Return list of all subclasses of Component (including Component).
67
+ def component_classes
68
+ return @component_classes if @component_classes
69
+
70
+ cc = Library.sort_class_tree(Component.subclasses)
71
+ @component_classes = cc if committed?
72
+
73
+ return cc
74
+ end
75
+
76
+ # Operate on Component class specifications gathered by meta.rb,
77
+ # and stored in the component classes.
78
+ def precommit
79
+ ## no need to precommit Component? Other abstract classes?
80
+ component_classes.each {|cl| cl.precommit}
81
+ ## optimization?
82
+ ## check if changed
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,1370 @@
1
+ module RedShift
2
+
3
+ class World
4
+ include CShadow
5
+ shadow_library RedShift.library
6
+ shadow_library_file "World"
7
+ shadow_library_source_file.include(Component.shadow_library_include_file)
8
+
9
+ shadow_library_include_file.declare :step_discrete_macros => '
10
+ #define INT2BOOL(i) (i ? Qtrue : Qfalse)
11
+
12
+ #define SWAP_VALUE(v, w) {VALUE ___tmp = v; v = w; w = ___tmp;}
13
+
14
+ #define EACH_COMP_DO(lc) \\
15
+ for (list = RARRAY(lc), list_i = list->len - 1; \\
16
+ list_i >= 0 && ( \\
17
+ comp = list->ptr[list_i], \\
18
+ comp_shdw = get_shadow(comp), \\
19
+ 1); \\
20
+ list_i--)
21
+
22
+ int dummy;
23
+ '.tabto(0)
24
+ # Note: EACH_COMP_DO(lc) block may use move_comp and remove_comp
25
+ # but it should (re)move none or all. Must have declarations for comp
26
+ # comp_shdw, list, and list_i in scope.
27
+
28
+ shadow_library_include_file.declare :cv_cache_entry => %{
29
+ typedef struct {
30
+ double *dbl_ptr;
31
+ double value;
32
+ } CVCacheEntry;
33
+ }
34
+
35
+ shadow_library_include_file.declare :link_cache_entry => %{
36
+ typedef struct {
37
+ ComponentShadow **link_ptr;
38
+ VALUE value;
39
+ } LinkCacheEntry;
40
+ }
41
+
42
+ shadow_library_include_file.declare :port_cache_entry => %{
43
+ typedef struct {
44
+ VALUE input_port;
45
+ VALUE other_port;
46
+ } PortCacheEntry;
47
+ }
48
+
49
+ # Initial size for the constant value cache.
50
+ CV_CACHE_SIZE = 64
51
+
52
+ # Initial size for the link cache.
53
+ LINK_CACHE_SIZE = 64
54
+
55
+ # Initial size for the port cache.
56
+ PORT_CACHE_SIZE = 64
57
+
58
+ World.subclasses.each do |sub|
59
+ file_name = CGenerator.make_c_name(sub.name).to_s
60
+ sub.shadow_library_file file_name
61
+ end
62
+
63
+ shadow_attr_accessor :curr_A => Array
64
+ shadow_attr_accessor :curr_P => Array
65
+ shadow_attr_accessor :curr_CR => Array
66
+ shadow_attr_accessor :curr_S => Array
67
+ shadow_attr_accessor :next_S => Array
68
+ shadow_attr_accessor :curr_T => Array
69
+ shadow_attr_accessor :active_E => Array
70
+ shadow_attr_accessor :prev_active_E => Array
71
+ shadow_attr_accessor :awake => Array
72
+ shadow_attr_accessor :prev_awake => Array
73
+ shadow_attr_accessor :strict_sleep => Array
74
+ shadow_attr_accessor :inert => Array
75
+ shadow_attr_accessor :diff_list => Array
76
+ shadow_attr_accessor :queue_sleep => Hash
77
+ protected \
78
+ :curr_A, :curr_P, :curr_CR, :curr_T,
79
+ :active_E=, :prev_active_E=, :awake=,
80
+ :strict_sleep=, :inert=, :diff_list=,
81
+ :queue_sleep=
82
+
83
+ shadow_attr_reader :time_step => "double time_step"
84
+ shadow_attr_accessor :zeno_limit => "long zeno_limit"
85
+ shadow_attr_accessor :step_count => "long step_count"
86
+ shadow_attr_accessor :clock_start => "double clock_start"
87
+ shadow_attr_accessor :clock_finish => "double clock_finish"
88
+ shadow_attr_accessor :zeno_counter => "long zeno_counter"
89
+ shadow_attr_reader :discrete_step => "long discrete_step"
90
+ shadow_attr_accessor :rk_level => "long rk_level"
91
+ shadow_attr_accessor :d_tick => "long d_tick"
92
+ shadow_attr_accessor :alg_nest => "long alg_nest"
93
+
94
+ shadow_attr_accessor :base_clock => "double base_clock"
95
+ shadow_attr_accessor :base_step_count =>
96
+ "long base_step_count"
97
+ protected :base_clock=, :base_step_count=
98
+
99
+ new_method.attr_code %{
100
+ shadow->rk_level = 0;
101
+ shadow->d_tick = 1;
102
+ shadow->alg_nest = 0;
103
+ } # d_tick=1 means alg flows need to be recalculated
104
+
105
+ shadow_struct.declare :constant_value_cache => %{
106
+ CVCacheEntry *constant_value_cache;
107
+ int cv_cache_size;
108
+ int cv_cache_used;
109
+ }
110
+ new_method.attr_code %{
111
+ shadow->constant_value_cache = 0;
112
+ shadow->cv_cache_size = 0;
113
+ shadow->cv_cache_used = 0;
114
+ }
115
+ free_function.free "free(shadow->constant_value_cache)"
116
+
117
+ shadow_struct.declare :link_cache => %{
118
+ LinkCacheEntry *link_cache;
119
+ int link_cache_size;
120
+ int link_cache_used;
121
+ }
122
+ ##should non-persist things like these get initialized in the alloc func, too?
123
+ new_method.attr_code %{
124
+ shadow->link_cache = 0;
125
+ shadow->link_cache_size = 0;
126
+ shadow->link_cache_used = 0;
127
+ }
128
+ free_function.free "free(shadow->link_cache)"
129
+
130
+ shadow_struct.declare :port_cache => %{
131
+ PortCacheEntry *port_cache;
132
+ int port_cache_size;
133
+ int port_cache_used;
134
+ }
135
+ new_method.attr_code %{
136
+ shadow->port_cache = 0;
137
+ shadow->port_cache_size = 0;
138
+ shadow->port_cache_used = 0;
139
+ }
140
+ free_function.free "free(shadow->port_cache)"
141
+
142
+ class << self
143
+ # Redefines World#new so that a library commit happens first.
144
+ def new(*args, &block)
145
+ commit # redefines World.new
146
+ new(*args, &block) # which is what this line calls
147
+ end
148
+ end
149
+
150
+ define_c_method :time_step= do
151
+ arguments :time_step
152
+ body %{
153
+ double new_time_step = NUM2DBL(time_step);
154
+ shadow->base_clock = shadow->base_clock +
155
+ (shadow->step_count - shadow->base_step_count) * shadow->time_step;
156
+ shadow->base_step_count = shadow->step_count;
157
+ shadow->time_step = new_time_step;
158
+ }
159
+ returns "shadow->time_step" ## needed?
160
+ end
161
+
162
+ define_c_method :clock do
163
+ returns %{
164
+ rb_float_new(
165
+ shadow->base_clock +
166
+ (shadow->step_count - shadow->base_step_count) * shadow->time_step)
167
+ }
168
+ end
169
+
170
+ # This is for when Component#world is nonpersistent
171
+ # _load_data_method.post_code %{
172
+ # rb_funcall(shadow->self, #{shadow_library_include_file.declare_symbol "__restore__world__refs"}, 0);
173
+ # }
174
+
175
+ define_c_method :bump_d_tick do
176
+ body "shadow->d_tick++"
177
+ end
178
+
179
+ slif = shadow_library_include_file
180
+ slif.declare :get_shadow => %{
181
+ inline static ComponentShadow *get_shadow(VALUE comp)
182
+ {
183
+ assert(RTEST(rb_obj_is_kind_of(comp, #{slif.declare_module CShadow})));
184
+ return (ComponentShadow *)DATA_PTR(comp);
185
+ }
186
+ }
187
+
188
+ define_c_method :step_continuous do
189
+ declare :locals => %{
190
+ VALUE comp_rb_ary[2], *comp_ary;
191
+ long len;
192
+ long var_count;
193
+ ContVar *var, *end_var;
194
+ long li, ci;
195
+ ComponentShadow *comp_shdw;
196
+ }.tabto(0)
197
+ body %{
198
+ comp_rb_ary[0] = shadow->awake;
199
+ comp_rb_ary[1] = shadow->inert;
200
+ for (li = 0; li < 2; li++) {
201
+ len = RARRAY(comp_rb_ary[li])->len;
202
+ comp_ary = RARRAY(comp_rb_ary[li])->ptr;
203
+ for (ci = 0; ci < len; ci++) {
204
+ Data_Get_Struct(comp_ary[ci], ComponentShadow, comp_shdw);
205
+ var_count = comp_shdw->var_count;
206
+ var = (ContVar *)(&FIRST_CONT_VAR(comp_shdw));
207
+ end_var = &var[var_count];
208
+
209
+ while (var < end_var) {
210
+ var->rk_level = 0;
211
+ if (!var->flow) {
212
+ var->value_1 = var->value_2 = var->value_3 = var->value_0;
213
+ }
214
+ var++;
215
+ }
216
+ }
217
+ }
218
+
219
+ for (shadow->rk_level = 1; shadow->rk_level <= 3; shadow->rk_level++) {
220
+ len = RARRAY(shadow->diff_list)->len;
221
+ comp_ary = RARRAY(shadow->diff_list)->ptr;
222
+ for (ci = 0; ci < len; ci++) {
223
+ Data_Get_Struct(comp_ary[ci], ComponentShadow, comp_shdw);
224
+
225
+ if (shadow->rk_level == 1 && !comp_shdw->has_diff) {
226
+ if (ci < len-1) {
227
+ comp_ary[ci] = comp_ary[len-1];
228
+ ci--;
229
+ }
230
+ len = RARRAY(shadow->diff_list)->len = len-1;
231
+ comp_shdw->diff_list = 0;
232
+ }
233
+ else {
234
+ var_count = comp_shdw->var_count;
235
+ var = (ContVar *)(&FIRST_CONT_VAR(comp_shdw));
236
+ end_var = &var[var_count];
237
+
238
+ while (var < end_var) {
239
+ if (var->flow &&
240
+ var->rk_level < shadow->rk_level &&
241
+ !var->algebraic)
242
+ (*var->flow)((ComponentShadow *)comp_shdw);
243
+ var++;
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ shadow->rk_level = 4;
250
+ for (li = 0; li < 2; li++) {
251
+ len = RARRAY(comp_rb_ary[li])->len;
252
+ comp_ary = RARRAY(comp_rb_ary[li])->ptr;
253
+ for (ci = 0; ci < len; ci++) {
254
+ Data_Get_Struct(comp_ary[ci], ComponentShadow, comp_shdw);
255
+ var_count = comp_shdw->var_count;
256
+ var = (ContVar *)(&FIRST_CONT_VAR(comp_shdw));
257
+ end_var = &var[var_count];
258
+
259
+ while (var < end_var) {
260
+ if (var->flow &&
261
+ var->rk_level < shadow->rk_level &&
262
+ !var->algebraic)
263
+ (*var->flow)((ComponentShadow *)comp_shdw);
264
+
265
+ if (var->rk_level == 4)
266
+ var->d_tick = 1; //# var will be current in discrete_step
267
+ else
268
+ var->d_tick = 0; //# var (if alg) will need to be evaled
269
+ var++;
270
+ }
271
+ }
272
+ }
273
+
274
+ shadow->d_tick = 1; //# alg flows need to be recalculated
275
+ shadow->rk_level = 0;
276
+ } # assumed that comp_ary[i] was a Component--enforced by World#create
277
+ end
278
+ private :step_continuous
279
+
280
+ ## define_c_function :my_instance_eval do
281
+ # shadow_library_source_file.define(:my_instance_eval).instance_eval do
282
+ # arguments "VALUE comp"
283
+ # return_type "VALUE"
284
+ # scope :static
285
+ # returns "rb_obj_instance_eval(0, 0, comp)"
286
+ # end
287
+ #
288
+ # shadow_library_source_file.define(:call_block).instance_eval do
289
+ # arguments "VALUE arg1", "VALUE block"
290
+ # return_type "VALUE"
291
+ # scope :static
292
+ # returns "rb_funcall(block, #{declare_symbol :call}, 0)"
293
+ # end
294
+
295
+ discrete_step_definer = proc do
296
+ parent.declare :static_locals => %{
297
+ static VALUE ExitState, GuardWrapperClass, ExprWrapperClass;
298
+ static VALUE ActionClass, EventClass, ResetClass, GuardClass;
299
+ static VALUE QMatchClass, ConnectClass;
300
+ static VALUE PostClass, DynamicEventClass, SyncClass;
301
+ }.tabto(0)
302
+
303
+ declare :locals => %{
304
+ VALUE comp;
305
+ ComponentShadow *comp_shdw;
306
+ VALUE *ptr;
307
+ long len;
308
+ long i;
309
+ struct RArray *list;
310
+ int list_i;
311
+ int did_reset;
312
+ }.tabto(0)
313
+
314
+ insteval_proc = declare_symbol :insteval_proc
315
+ capa = RUBY_VERSION.to_f >= 1.7 ? "aux.capa" : "capa"
316
+ epi = Component::EventPhaseItem
317
+ spi = Component::SyncPhaseItem
318
+
319
+ parent.declare :step_discrete_subs => %{
320
+ inline static VALUE cur_syncs(ComponentShadow *comp_shdw)
321
+ {
322
+ VALUE syncs = RARRAY(comp_shdw->trans)->ptr[#{Transition::S_IDX}];
323
+ assert(syncs == Qnil || RBASIC(syncs)->klass == SyncClass);
324
+ return syncs;
325
+ }
326
+ inline static VALUE cur_actions(ComponentShadow *comp_shdw)
327
+ {
328
+ VALUE actions = RARRAY(comp_shdw->trans)->ptr[#{Transition::A_IDX}];
329
+ assert(actions == Qnil || RBASIC(actions)->klass == ActionClass);
330
+ return actions;
331
+ }
332
+ inline static VALUE cur_posts(ComponentShadow *comp_shdw)
333
+ {
334
+ VALUE posts = RARRAY(comp_shdw->trans)->ptr[#{Transition::P_IDX}];
335
+ assert(posts == Qnil || RBASIC(posts)->klass == PostClass);
336
+ return posts;
337
+ }
338
+ inline static VALUE cur_events(ComponentShadow *comp_shdw)
339
+ {
340
+ VALUE events = RARRAY(comp_shdw->trans)->ptr[#{Transition::E_IDX}];
341
+ assert(events == Qnil || RBASIC(events)->klass == EventClass);
342
+ return events;
343
+ }
344
+ inline static VALUE cur_resets(ComponentShadow *comp_shdw)
345
+ {
346
+ VALUE resets = RARRAY(comp_shdw->trans)->ptr[#{Transition::R_IDX}];
347
+ assert(resets == Qnil || RBASIC(resets)->klass == ResetClass);
348
+ return resets;
349
+ }
350
+ inline static VALUE cur_connects(ComponentShadow *comp_shdw)
351
+ {
352
+ VALUE connects = RARRAY(comp_shdw->trans)->ptr[#{Transition::C_IDX}];
353
+ assert(connects == Qnil || RBASIC(connects)->klass == ConnectClass);
354
+ return connects;
355
+ }
356
+ inline static void move_comp(VALUE comp, VALUE list, VALUE next_list)
357
+ {
358
+ struct RArray *nl = RARRAY(next_list);
359
+ assert(RARRAY(list)->ptr[RARRAY(list)->len-1] == comp);
360
+ if (nl->len == nl->#{capa})
361
+ rb_ary_store(next_list, nl->len, comp);
362
+ else
363
+ nl->ptr[nl->len++] = comp;
364
+ --RARRAY(list)->len;
365
+ }
366
+ inline static void move_comp_to_hash(VALUE comp, VALUE list, VALUE hash)
367
+ {
368
+ struct RArray *l = RARRAY(list);
369
+ assert(l->ptr[l->len-1] == comp);
370
+ rb_hash_aset(hash, comp, Qtrue);
371
+ --l->len;
372
+ }
373
+ inline static void move_all_comps(VALUE list, VALUE next_list)
374
+ { //## this could be faster using memcpy
375
+ struct RArray *l = RARRAY(list);
376
+ while (l->len)
377
+ move_comp(l->ptr[l->len-1], list, next_list);
378
+ }
379
+ inline static void remove_comp(VALUE comp, VALUE list,
380
+ #{World.shadow_struct.name} *shadow)
381
+ {
382
+ ComponentShadow *comp_shdw = get_shadow(comp);
383
+ assert(RARRAY(list)->ptr[RARRAY(list)->len-1] == comp);
384
+ assert(comp_shdw->world == shadow);
385
+ comp_shdw->world = 0;
386
+ --RARRAY(list)->len;
387
+ }
388
+ inline static double eval_expr(VALUE comp, VALUE expr)
389
+ {
390
+ double (*fn)(ComponentShadow *), rslt;
391
+ assert(rb_obj_is_kind_of(expr, ExprWrapperClass));
392
+ fn = ((#{RedShift::Component::ExprWrapper.shadow_struct.name} *)
393
+ get_shadow(expr))->expr;
394
+ rslt = (*fn)(get_shadow(comp));
395
+ return rslt;
396
+ }
397
+ inline static ComponentShadow *eval_comp_expr(VALUE comp, VALUE expr)
398
+ {
399
+ ComponentShadow *(*fn)(ComponentShadow *);
400
+ ComponentShadow *rslt;
401
+ assert(rb_obj_is_kind_of(expr, ExprWrapperClass));
402
+ fn = ((#{RedShift::Component::ExprWrapper.shadow_struct.name} *)
403
+ get_shadow(expr))->expr;
404
+ rslt = (*fn)(get_shadow(comp));
405
+ return rslt;
406
+ }
407
+ inline static int test_cexpr_guard(VALUE comp, VALUE guard)
408
+ {
409
+ int (*fn)(ComponentShadow *), rslt;
410
+ assert(rb_obj_is_kind_of(guard, GuardWrapperClass));
411
+ fn = ((#{RedShift::Component::GuardWrapper.shadow_struct.name} *)
412
+ get_shadow(guard))->guard;
413
+ rslt = (*fn)(get_shadow(comp));
414
+ return rslt;
415
+ }
416
+ inline static int guard_enabled(VALUE comp, VALUE guards,
417
+ int discrete_step)
418
+ {
419
+ int i;
420
+ VALUE kl;
421
+ assert(BUILTIN_TYPE(guards) == T_ARRAY);
422
+ for (i = 0; i < RARRAY(guards)->len; i++) {
423
+ VALUE guard = RARRAY(guards)->ptr[i];
424
+
425
+ if (SYMBOL_P(guard)) {
426
+ if (!RTEST(rb_funcall(comp, SYM2ID(guard), 0)))
427
+ return 0;
428
+ }
429
+ else {
430
+ switch (BUILTIN_TYPE(guard)) {
431
+ case T_DATA:
432
+ if (RBASIC(guard)->klass == rb_cProc) {
433
+ if (!RTEST(rb_funcall(comp, #{insteval_proc}, 1, guard)))
434
+ return 0; //## faster way to call instance_eval ???
435
+ }
436
+ else {
437
+ assert(!rb_obj_is_kind_of(guard, rb_cProc));
438
+ if (!test_cexpr_guard(comp, guard))
439
+ return 0;
440
+ }
441
+ break;
442
+
443
+ case T_ARRAY:
444
+ kl = RBASIC(guard)->klass;
445
+ if (kl == QMatchClass) {
446
+ int len = RARRAY(guard)->len;
447
+ VALUE *ptr = RARRAY(guard)->ptr;
448
+ assert(len > 0);
449
+ VALUE queue_name = ptr[0];
450
+ VALUE queue = rb_funcall(comp, SYM2ID(queue_name), 0);
451
+ if (!RTEST(rb_funcall2(queue, #{declare_symbol :head_matches},
452
+ len-1, &ptr[1])))
453
+ return 0;
454
+ }
455
+ else {
456
+ rb_raise(#{declare_class StandardError},
457
+ "Bad array class in guard_enabled().");
458
+ }
459
+ break;
460
+
461
+ case T_CLASS:
462
+ assert(RTEST(rb_funcall(guard, #{declare_symbol "<"},
463
+ 1, GuardWrapperClass)));
464
+ guard = rb_funcall(guard, #{declare_symbol :instance}, 0);
465
+ RARRAY(guards)->ptr[i] = guard;
466
+ if (!test_cexpr_guard(comp, guard))
467
+ return 0;
468
+ break;
469
+
470
+ default:
471
+ assert(0);
472
+ }
473
+ }
474
+ }
475
+ return 1;
476
+ }
477
+
478
+ inline static int comp_can_sync(ComponentShadow *comp_shdw,
479
+ #{World.shadow_struct.name} *shadow)
480
+ {
481
+ int i, j;
482
+ int can_sync = 1;
483
+ VALUE syncs = cur_syncs(comp_shdw);
484
+ assert(RTEST(syncs));
485
+
486
+ for (i = RARRAY(syncs)->len - 1; i >= 0; i--) {
487
+ VALUE sync = RARRAY(syncs)->ptr[i];
488
+ assert(RARRAY(sync)->len == 3);
489
+ int link_offset = FIX2INT(RARRAY(sync)->ptr[#{spi::LINK_OFFSET_IDX}]);
490
+ VALUE event = RARRAY(sync)->ptr[#{spi::EVENT_IDX}];
491
+ ComponentShadow *link_shdw =
492
+ *(ComponentShadow **)(((char *)comp_shdw) + link_offset);
493
+
494
+ if (!link_shdw || !RTEST(link_shdw->trans)) {
495
+ can_sync = 0;
496
+ break;
497
+ }
498
+
499
+ int found = 0;
500
+ VALUE link_events = cur_events(link_shdw);
501
+ if (RTEST(link_events)) {
502
+ VALUE *ptr = RARRAY(link_events)->ptr;
503
+ long len = RARRAY(link_events)->len;
504
+
505
+ for (j = len; j > 0; j--, ptr++) {
506
+ VALUE link_event = RARRAY(*ptr)->ptr[#{epi::E_IDX}];
507
+ if (link_event == event) {
508
+ found = 1;
509
+ break;
510
+ }
511
+ }
512
+ }
513
+
514
+ if (!found) {
515
+ can_sync = 0;
516
+ break;
517
+ }
518
+ }
519
+
520
+ //%% hook_can_sync(comp_shdw->self, INT2BOOL(can_sync));
521
+ return can_sync;
522
+ }
523
+
524
+ inline static int eval_events(ComponentShadow *comp_shdw,
525
+ #{World.shadow_struct.name} *shadow)
526
+ {
527
+ VALUE events = cur_events(comp_shdw);
528
+ int has_events = RTEST(events);
529
+
530
+ if (has_events) {
531
+ VALUE *ptr = RARRAY(events)->ptr;
532
+ long len = RARRAY(events)->len;
533
+ int i;
534
+ VALUE comp = comp_shdw->self;
535
+
536
+ for (i = len; i > 0; i--, ptr++) {
537
+ int event_idx = FIX2INT(RARRAY(*ptr)->ptr[#{epi::I_IDX}]);
538
+ VALUE event_val = RARRAY(*ptr)->ptr[#{epi::V_IDX}];
539
+
540
+ //## maybe this distinction should be made clear in the array
541
+ //## itself, with a numeric switch, say.
542
+ if (TYPE(event_val) == T_DATA &&
543
+ rb_obj_is_kind_of(event_val, DynamicEventClass))
544
+ event_val = rb_funcall(comp, #{insteval_proc}, 1, event_val);
545
+ else if (rb_obj_is_kind_of(event_val, ExprWrapperClass))
546
+ event_val = rb_float_new(eval_expr(comp, event_val));
547
+
548
+ //%% hook_eval_event(comp, RARRAY(*ptr)->ptr[#{epi::E_IDX}],
549
+ //%% event_val);
550
+ RARRAY(comp_shdw->next_event_values)->ptr[event_idx] = event_val;
551
+ }
552
+ }
553
+
554
+ return has_events;
555
+ }
556
+
557
+ inline static void cache_new_constant_value(
558
+ double *dbl_ptr, double value,
559
+ #{World.shadow_struct.name} *shadow)
560
+ {
561
+ CVCacheEntry *entry;
562
+
563
+ if (!shadow->constant_value_cache) {
564
+ int n = #{CV_CACHE_SIZE};
565
+ shadow->constant_value_cache = malloc(n*sizeof(CVCacheEntry));
566
+ shadow->cv_cache_size = n;
567
+ shadow->cv_cache_used = 0;
568
+ }
569
+ if (shadow->cv_cache_used == shadow->cv_cache_size) {
570
+ int n_bytes;
571
+ shadow->cv_cache_size *= 2;
572
+ n_bytes = shadow->cv_cache_size*sizeof(CVCacheEntry);
573
+ shadow->constant_value_cache = realloc(
574
+ shadow->constant_value_cache, n_bytes);
575
+ if (!shadow->constant_value_cache) {
576
+ rb_raise(#{declare_class NoMemoryError},
577
+ "Out of memory trying to allocate %d bytes for CV cache.",
578
+ n_bytes);
579
+ }
580
+ }
581
+ entry = &shadow->constant_value_cache[shadow->cv_cache_used];
582
+ entry->dbl_ptr = dbl_ptr;
583
+ entry->value = value;
584
+ shadow->cv_cache_used += 1;
585
+ }
586
+
587
+ inline static int assign_new_constant_values(
588
+ #{World.shadow_struct.name} *shadow)
589
+ {
590
+ int did_reset = shadow->cv_cache_used;
591
+
592
+ if (shadow->cv_cache_used) {
593
+ int i;
594
+ CVCacheEntry *entry;
595
+
596
+ entry = shadow->constant_value_cache;
597
+ for (i = shadow->cv_cache_used; i > 0; i--, entry++) {
598
+ *entry->dbl_ptr = entry->value;
599
+ }
600
+ shadow->cv_cache_used = 0;
601
+ }
602
+
603
+ return did_reset;
604
+ }
605
+
606
+ inline static void cache_new_link(
607
+ ComponentShadow **link_ptr, VALUE value,
608
+ #{World.shadow_struct.name} *shadow)
609
+ {
610
+ LinkCacheEntry *entry;
611
+
612
+ if (!shadow->link_cache) {
613
+ int n = #{LINK_CACHE_SIZE};
614
+ shadow->link_cache = malloc(n*sizeof(LinkCacheEntry));
615
+ shadow->link_cache_size = n;
616
+ shadow->link_cache_used = 0;
617
+ }
618
+ if (shadow->link_cache_used == shadow->link_cache_size) {
619
+ int n_bytes;
620
+ shadow->link_cache_size *= 2;
621
+ n_bytes = shadow->link_cache_size*sizeof(LinkCacheEntry);
622
+ shadow->link_cache = realloc(shadow->link_cache, n_bytes);
623
+ if (!shadow->link_cache) {
624
+ rb_raise(#{declare_class NoMemoryError},
625
+ "Out of memory trying to allocate %d bytes for link cache.",
626
+ n_bytes);
627
+ }
628
+ }
629
+ entry = &shadow->link_cache[shadow->link_cache_used];
630
+ entry->link_ptr = link_ptr;
631
+ entry->value = value;
632
+ shadow->link_cache_used += 1;
633
+ }
634
+
635
+ inline static int assign_new_links(
636
+ #{World.shadow_struct.name} *shadow)
637
+ {
638
+ int did_reset = shadow->link_cache_used;
639
+
640
+ if (shadow->link_cache_used) {
641
+ int i;
642
+ LinkCacheEntry *entry;
643
+
644
+ entry = shadow->link_cache;
645
+ for (i = shadow->link_cache_used; i > 0; i--, entry++) {
646
+ ComponentShadow *comp_shdw;
647
+ if (NIL_P(entry->value))
648
+ comp_shdw = 0;
649
+ else
650
+ comp_shdw = get_shadow(entry->value);
651
+ *entry->link_ptr = comp_shdw;
652
+ }
653
+ shadow->link_cache_used = 0;
654
+ }
655
+
656
+ return did_reset;
657
+ }
658
+
659
+ inline static void cache_new_port(VALUE input_port, VALUE other_port,
660
+ #{World.shadow_struct.name} *shadow)
661
+ {
662
+ PortCacheEntry *entry;
663
+
664
+ if (!shadow->port_cache) {
665
+ int n = #{PORT_CACHE_SIZE};
666
+ shadow->port_cache = malloc(n*sizeof(PortCacheEntry));
667
+ shadow->port_cache_size = n;
668
+ shadow->port_cache_used = 0;
669
+ }
670
+ if (shadow->port_cache_used == shadow->port_cache_size) {
671
+ int n_bytes;
672
+ shadow->port_cache_size *= 2;
673
+ n_bytes = shadow->port_cache_size*sizeof(PortCacheEntry);
674
+ shadow->port_cache = realloc(shadow->port_cache, n_bytes);
675
+ if (!shadow->port_cache) {
676
+ rb_raise(#{declare_class NoMemoryError},
677
+ "Out of memory trying to allocate %d bytes for port cache.",
678
+ n_bytes);
679
+ }
680
+ }
681
+ entry = &shadow->port_cache[shadow->port_cache_used];
682
+ entry->input_port = input_port;
683
+ entry->other_port = other_port;
684
+ shadow->port_cache_used += 1;
685
+ }
686
+
687
+ inline static int assign_new_ports(
688
+ #{World.shadow_struct.name} *shadow)
689
+ {
690
+ int did_reset = shadow->port_cache_used;
691
+
692
+ if (shadow->port_cache_used) {
693
+ int i;
694
+ PortCacheEntry *entry;
695
+
696
+ entry = shadow->port_cache;
697
+ for (i = shadow->port_cache_used; i > 0; i--, entry++) {
698
+ rb_funcall(entry->input_port, #{declare_symbol :_connect}, 1,
699
+ entry->other_port);
700
+ }
701
+ shadow->port_cache_used = 0;
702
+ }
703
+
704
+ return did_reset;
705
+ }
706
+
707
+ inline static int eval_continuous_resets(ComponentShadow *comp_shdw,
708
+ #{World.shadow_struct.name} *shadow)
709
+ {
710
+ VALUE resets = cur_resets(comp_shdw);
711
+ VALUE cont_resets;
712
+ int has_cont_resets;
713
+
714
+ if (!RTEST(resets))
715
+ return 0;
716
+
717
+ cont_resets = RARRAY(resets)->ptr[0];
718
+ has_cont_resets = RTEST(cont_resets);
719
+
720
+ if (has_cont_resets) {
721
+ VALUE *ptr = RARRAY(cont_resets)->ptr;
722
+ long len = RARRAY(cont_resets)->len;
723
+ int i;
724
+ VALUE comp = comp_shdw->self;
725
+ ContVar *var = (ContVar *)&FIRST_CONT_VAR(comp_shdw);
726
+ assert(len <= comp_shdw->var_count);
727
+
728
+ for (i = 0; i < len; i++, var++, ptr++) {
729
+ VALUE reset = *ptr;
730
+ if (reset == Qnil) {
731
+ var->reset = 0;
732
+ }
733
+ else {
734
+ double new_value;
735
+
736
+ //## if (var->algebraic)
737
+ //## rb_raise(#{declare_class AlgebraicAssignmentError},
738
+ //## "reset of variable with algebraic flow"); //## do statically?
739
+
740
+ switch(TYPE(reset)) {
741
+ case T_FLOAT:
742
+ new_value = RFLOAT(reset)->value;
743
+ break;
744
+ default:
745
+ if (RBASIC(reset)->klass == rb_cProc) {
746
+ VALUE val = rb_funcall(comp, #{insteval_proc}, 1, reset);
747
+ switch(TYPE(val)) {
748
+ case T_FLOAT:
749
+ new_value = RFLOAT(val)->value;
750
+ break;
751
+ case T_FIXNUM:
752
+ new_value = FIX2INT(val);
753
+ break;
754
+ default:
755
+ rs_raise(#{declare_class VarTypeError}, comp,
756
+ "tried to reset cont var with %s.",
757
+ STR2CSTR(rb_funcall(
758
+ rb_funcall(val, #{declare_symbol :class}, 0),
759
+ #{declare_symbol :to_s},
760
+ 0))
761
+ );
762
+ }
763
+ }
764
+ else
765
+ new_value = eval_expr(comp, reset);
766
+ }
767
+
768
+ //%% hook_eval_reset_continuous(comp,
769
+ //%% rb_funcall(comp_shdw->cont_state->self,//
770
+ //%% #{declare_symbol :var_at_index},1,INT2NUM(i)),
771
+ //%% rb_float_new(new_value));
772
+ var->value_1 = new_value;
773
+ var->reset = 1;
774
+ }
775
+ }
776
+ }
777
+
778
+ return has_cont_resets;
779
+ }
780
+
781
+ inline static int eval_constant_resets(ComponentShadow *comp_shdw,
782
+ #{World.shadow_struct.name} *shadow)
783
+ {
784
+ VALUE resets = cur_resets(comp_shdw);
785
+ VALUE const_resets;
786
+ VALUE link_resets;
787
+ int has_const_resets;
788
+ int has_link_resets;
789
+ int i;
790
+ VALUE comp;
791
+
792
+ if (!RTEST(resets))
793
+ return 0;
794
+
795
+ const_resets = RARRAY(resets)->ptr[1];
796
+ link_resets = RARRAY(resets)->ptr[2];
797
+ has_const_resets = RTEST(const_resets);
798
+ has_link_resets = RTEST(link_resets);
799
+ comp = comp_shdw->self;
800
+
801
+ if (has_const_resets) {
802
+ VALUE *ptr = RARRAY(const_resets)->ptr;
803
+ long len = RARRAY(const_resets)->len;
804
+
805
+ for (i = 0; i < len; i++) {
806
+ VALUE pair = ptr[i];
807
+ int offset = NUM2INT(RARRAY(pair)->ptr[0]);
808
+ VALUE reset = RARRAY(pair)->ptr[1];
809
+ double new_value;
810
+
811
+ switch(TYPE(reset)) {
812
+ case T_FLOAT:
813
+ new_value = RFLOAT(reset)->value;
814
+ break;
815
+ default:
816
+ if (RBASIC(reset)->klass == rb_cProc)
817
+ new_value =
818
+ NUM2DBL(rb_funcall(comp, #{insteval_proc}, 1, reset));
819
+ else
820
+ new_value = eval_expr(comp, reset);
821
+ }
822
+
823
+ //%% hook_eval_reset_constant(comp,
824
+ //%% RARRAY(pair)->ptr[2], rb_float_new(new_value));
825
+ cache_new_constant_value(
826
+ (double *)((char *)comp_shdw + offset),
827
+ new_value, shadow);
828
+ }
829
+ }
830
+
831
+ if (has_link_resets) {
832
+ VALUE *ptr = RARRAY(link_resets)->ptr;
833
+ long len = RARRAY(link_resets)->len;
834
+
835
+ for (i = 0; i < len; i++) {
836
+ VALUE pair = ptr[i];
837
+ int offset = NUM2INT(RARRAY(pair)->ptr[0]);
838
+ VALUE reset = RARRAY(pair)->ptr[1];
839
+ VALUE new_value;
840
+
841
+ if (rb_obj_is_kind_of(reset, ExprWrapperClass)) {
842
+ ComponentShadow *new_sh;
843
+ new_sh = (ComponentShadow *) eval_comp_expr(comp, reset);
844
+ new_value = new_sh ? new_sh->self : Qnil;
845
+ }
846
+ else if (reset == Qnil) {
847
+ new_value = reset;
848
+ }
849
+ else if (RBASIC(reset)->klass == rb_cProc) {
850
+ new_value =
851
+ (VALUE)(rb_funcall(comp, #{insteval_proc}, 1, reset));
852
+ }
853
+ else {
854
+ new_value = reset; // will raise exception below
855
+ }
856
+
857
+ if (!NIL_P(new_value) &&
858
+ rb_obj_is_kind_of(new_value, RARRAY(pair)->ptr[3]) != Qtrue) {
859
+ VALUE to_s = #{declare_symbol :to_s};
860
+ rs_raise(#{declare_class LinkTypeError}, comp_shdw->self,
861
+ "tried to reset %s, which is declared %s, with %s.",
862
+ STR2CSTR(rb_funcall(RARRAY(pair)->ptr[2], to_s, 0)),
863
+ STR2CSTR(rb_funcall(RARRAY(pair)->ptr[3], to_s, 0)),
864
+ STR2CSTR(rb_funcall(
865
+ rb_funcall(new_value, #{declare_symbol :class}, 0), to_s, 0))
866
+ );
867
+ }
868
+
869
+ //%% hook_eval_reset_link(comp,
870
+ //%% RARRAY(pair)->ptr[2], (VALUE)new_value);
871
+ cache_new_link(
872
+ (ComponentShadow **)((char *)comp_shdw + offset),
873
+ new_value, shadow);
874
+ }
875
+ }
876
+
877
+ return has_const_resets || has_link_resets;
878
+ }
879
+
880
+ inline static int eval_port_connects(ComponentShadow *comp_shdw,
881
+ #{World.shadow_struct.name} *shadow)
882
+ {
883
+ VALUE connects = cur_connects(comp_shdw);
884
+
885
+ if (!RTEST(connects))
886
+ return 0;
887
+ else {
888
+ int i;
889
+ VALUE comp = comp_shdw->self;
890
+ VALUE *ptr = RARRAY(connects)->ptr;
891
+ long len = RARRAY(connects)->len;
892
+
893
+ for (i = 0; i < len; i++) {
894
+ VALUE pair = ptr[i];
895
+ VALUE input_var = RARRAY(pair)->ptr[0];
896
+ VALUE connect_spec = RARRAY(pair)->ptr[1];
897
+ VALUE input_port;
898
+ VALUE other_port;
899
+
900
+ input_port = rb_funcall(comp, #{declare_symbol :port}, 1, input_var);
901
+ if (connect_spec == Qnil) {
902
+ other_port = Qnil;
903
+ }
904
+ else if (RBASIC(connect_spec)->klass == rb_cProc) {
905
+ other_port = rb_funcall(comp, #{insteval_proc}, 1, connect_spec);
906
+ }
907
+ else {
908
+ // ## unimpl.
909
+ }
910
+
911
+ //%% hook_eval_port_connect(comp,
912
+ //%% input_port, other_port);
913
+ cache_new_port(input_port, other_port, shadow);
914
+ }
915
+ return 1;
916
+ }
917
+ }
918
+
919
+ inline static int assign_new_cont_values(ComponentShadow *comp_shdw)
920
+ {
921
+ VALUE resets = cur_resets(comp_shdw);
922
+ VALUE cont_resets;
923
+ ContVar *var;
924
+ int did_reset;
925
+ long len;
926
+ long i;
927
+
928
+ if (!RTEST(resets))
929
+ return 0;
930
+
931
+ cont_resets = RARRAY(resets)->ptr[0];
932
+ var = (ContVar *)&FIRST_CONT_VAR(comp_shdw);
933
+ did_reset = 0;
934
+
935
+ len = RARRAY(cont_resets)->len;
936
+ for (i = len; i > 0; i--, var++) {
937
+ if (var->reset) {
938
+ var->reset = 0;
939
+ var->value_0 = var->value_1;
940
+ did_reset = 1;
941
+ }
942
+ }
943
+ return did_reset;
944
+ }
945
+
946
+ inline static void do_actions(ComponentShadow *comp_shdw, VALUE actions,
947
+ #{World.shadow_struct.name} *shadow)
948
+ {
949
+ long i;
950
+ VALUE comp = comp_shdw->self;
951
+
952
+ assert(RTEST(actions));
953
+
954
+ for (i = 0; i < RARRAY(actions)->len; i++) {
955
+ VALUE val = RARRAY(actions)->ptr[i];
956
+ //%% hook_call_action(comp, val);
957
+
958
+ if (SYMBOL_P(val))
959
+ rb_funcall(comp, SYM2ID(val), 0);
960
+ else
961
+ rb_funcall(comp, #{insteval_proc}, 1, val);
962
+ //## this tech. could be applied in EVENT and RESET.
963
+ //## also, component-gen can make use of this optimization
964
+ //## for procs, using code similar to that for guards.
965
+ //# rb_obj_instance_eval(1, &RARRAY(actions)->ptr[i], comp);
966
+ //# rb_iterate(my_instance_eval, comp, call_block, RARRAY(actions)->ptr[i]);
967
+ }
968
+ }
969
+
970
+ inline static void update_all_alg_vars(ComponentShadow *comp_shdw,
971
+ #{World.shadow_struct.name} *shadow)
972
+ {
973
+ ContVar *vars = (ContVar *)&FIRST_CONT_VAR(comp_shdw);
974
+ long count = comp_shdw->var_count;
975
+ long i;
976
+ for(i = 0; i < count; i++) {
977
+ ContVar *var = &vars[i];
978
+ if (var->algebraic &&
979
+ (var->strict ? var->d_tick == 0 :
980
+ var->d_tick != shadow->d_tick)) {
981
+ var->flow(comp_shdw);
982
+ }
983
+ }
984
+ }
985
+
986
+ inline static void start_trans(ComponentShadow *comp_shdw,
987
+ #{World.shadow_struct.name} *shadow,
988
+ VALUE trans, VALUE dest)
989
+ {
990
+ comp_shdw->trans = trans;
991
+ comp_shdw->dest = dest;
992
+ //%% hook_start_transition(comp_shdw->self, trans, dest);
993
+ }
994
+
995
+ inline static void finish_trans(ComponentShadow *comp_shdw,
996
+ #{World.shadow_struct.name} *shadow)
997
+ { //%% hook_finish_transition(comp_shdw->self, comp_shdw->trans,
998
+ //%% comp_shdw->dest);
999
+ if (comp_shdw->state != comp_shdw->dest) {
1000
+ update_all_alg_vars(comp_shdw, shadow);
1001
+ comp_shdw->state = comp_shdw->dest;
1002
+ rs_update_cache(comp_shdw);
1003
+ comp_shdw->checked = 0;
1004
+ }
1005
+ comp_shdw->trans = Qnil;
1006
+ comp_shdw->dest = Qnil;
1007
+ }
1008
+
1009
+ inline static void abort_trans(ComponentShadow *comp_shdw)
1010
+ {
1011
+ comp_shdw->trans = Qnil;
1012
+ comp_shdw->dest = Qnil;
1013
+ }
1014
+
1015
+ inline static void check_strict(ComponentShadow *comp_shdw)
1016
+ {
1017
+ ContVar *vars = (ContVar *)&FIRST_CONT_VAR(comp_shdw);
1018
+ long count = comp_shdw->var_count;
1019
+ long i;
1020
+
1021
+ for(i = 0; i < count; i++) {
1022
+ ContVar *var = &vars[i];
1023
+ if (var->ck_strict) {
1024
+ var->ck_strict = 0;
1025
+ (*var->flow)(comp_shdw);
1026
+ if (var->value_0 != var->value_1) {
1027
+ rb_funcall(comp_shdw->self,
1028
+ #{declare_symbol :handle_strictness_error}, 3, INT2NUM(i),
1029
+ rb_float_new(var->value_0), rb_float_new(var->value_1));
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+
1035
+ inline static void check_guards(#{World.shadow_struct.name} *shadow,
1036
+ int sync_retry)
1037
+ {
1038
+ VALUE comp;
1039
+ ComponentShadow *comp_shdw;
1040
+ struct RArray *list;
1041
+ int list_i;
1042
+ VALUE *ptr;
1043
+ long len, cur;
1044
+
1045
+ EACH_COMP_DO(shadow->prev_awake) {
1046
+ int enabled = 0;
1047
+
1048
+ if (shadow->discrete_step == 0)
1049
+ comp_shdw->checked = 0;
1050
+
1051
+ len = RARRAY(comp_shdw->outgoing)->len - 1; //# last is flags
1052
+ cur = len;
1053
+
1054
+ if (len == 0) {
1055
+ move_comp(comp, shadow->prev_awake, shadow->inert);
1056
+ continue;
1057
+ }
1058
+
1059
+ ptr = RARRAY(comp_shdw->outgoing)->ptr;
1060
+ if (sync_retry)
1061
+ cur -= 4 * comp_shdw->tmp.trans.idx;
1062
+ else
1063
+ comp_shdw->tmp.trans.idx = 0;
1064
+
1065
+ while (cur >= 4) {
1066
+ VALUE trans, dest, guard, strict;
1067
+
1068
+ strict = ptr[--cur];
1069
+ guard = ptr[--cur];
1070
+
1071
+ enabled = !RTEST(guard) ||
1072
+ ((comp_shdw->checked && RTEST(strict)) ? 0 :
1073
+ guard_enabled(comp, guard, shadow->discrete_step));
1074
+
1075
+ //%% hook_eval_guard(comp, guard, INT2BOOL(enabled),
1076
+ //%% ptr[cur-2], ptr[cur-1]);
1077
+
1078
+ if (enabled) {
1079
+ dest = ptr[--cur];
1080
+ trans = ptr[--cur];
1081
+ start_trans(comp_shdw, shadow, trans, dest);
1082
+ if (RTEST(cur_syncs(comp_shdw))) {
1083
+ move_comp(comp, shadow->prev_awake, shadow->curr_S);
1084
+ comp_shdw->tmp.trans.idx = (len - cur)/4;
1085
+ }
1086
+ else
1087
+ move_comp(comp, shadow->prev_awake, shadow->curr_T);
1088
+ break;
1089
+ }
1090
+ else
1091
+ cur -= 2;
1092
+ }
1093
+
1094
+ if (!enabled) {
1095
+ VALUE qrc;
1096
+ if (comp_shdw->strict)
1097
+ move_comp(comp, shadow->prev_awake, shadow->strict_sleep);
1098
+ else if (comp_shdw->sleepable &&
1099
+ (qrc = rb_ivar_get(comp, #{declare_symbol :@queue_ready_count}),
1100
+ qrc == Qnil || qrc == INT2FIX(0))) {
1101
+ move_comp_to_hash(comp, shadow->prev_awake, shadow->queue_sleep);
1102
+ }
1103
+ else
1104
+ move_comp(comp, shadow->prev_awake, shadow->awake);
1105
+ comp_shdw->checked = 1;
1106
+ }
1107
+ }
1108
+ assert(RARRAY(shadow->prev_awake)->len == 0);
1109
+ }
1110
+
1111
+ inline static void do_sync_phase(#{World.shadow_struct.name} *shadow)
1112
+ {
1113
+ VALUE comp;
1114
+ ComponentShadow *comp_shdw;
1115
+ struct RArray *list;
1116
+ int list_i;
1117
+ int changed;
1118
+
1119
+ do {
1120
+ changed = 0;
1121
+ EACH_COMP_DO(shadow->curr_S) {
1122
+ if (comp_can_sync(comp_shdw, shadow)) {
1123
+ move_comp(comp, shadow->curr_S, shadow->next_S);
1124
+ }
1125
+ else {
1126
+ changed = 1;
1127
+ abort_trans(comp_shdw);
1128
+ move_comp(comp, shadow->curr_S, shadow->prev_awake);
1129
+ }
1130
+ }
1131
+
1132
+ assert(RARRAY(shadow->curr_S)->len == 0);
1133
+ SWAP_VALUE(shadow->curr_S, shadow->next_S);
1134
+ //%% hook_sync_step(shadow->curr_S, INT2BOOL(changed));
1135
+ } while (changed);
1136
+
1137
+ move_all_comps(shadow->curr_S, shadow->curr_T);
1138
+ }
1139
+
1140
+ }.tabto(0)
1141
+
1142
+ comp_id = declare_class RedShift::Component
1143
+ get_const = proc {|k| "rb_const_get(#{comp_id}, #{declare_symbol k})"}
1144
+ init %{
1145
+ ExitState = #{get_const[:Exit]};
1146
+ ActionClass = #{get_const[:ActionPhase]};
1147
+ PostClass = #{get_const[:PostPhase]};
1148
+ EventClass = #{get_const[:EventPhase]};
1149
+ ResetClass = #{get_const[:ResetPhase]};
1150
+ ConnectClass = #{get_const[:ConnectPhase]};
1151
+ GuardClass = #{get_const[:GuardPhase]};
1152
+ SyncClass = #{get_const[:SyncPhase]};
1153
+ QMatchClass = #{get_const[:QMatch]};
1154
+ GuardWrapperClass = #{get_const[:GuardWrapper]};
1155
+ ExprWrapperClass = #{get_const[:ExprWrapper]};
1156
+ DynamicEventClass = #{get_const[:DynamicEventValue]};
1157
+ }
1158
+
1159
+ body %{
1160
+ //%% hook_begin();
1161
+ shadow->zeno_counter = 0;
1162
+
1163
+ for (shadow->discrete_step = 0 ;; shadow->discrete_step++) {
1164
+ //%% hook_begin_step();
1165
+ int sync_retry = 0;
1166
+
1167
+ SWAP_VALUE(shadow->prev_awake, shadow->awake);
1168
+
1169
+ while (RARRAY(shadow->prev_awake)->len) {
1170
+ //%% hook_enter_guard_phase();
1171
+ check_guards(shadow, sync_retry);
1172
+ //%% hook_leave_guard_phase();
1173
+
1174
+ //%% hook_enter_sync_phase();
1175
+ do_sync_phase(shadow);
1176
+ //%% hook_leave_sync_phase();
1177
+ sync_retry = 1;
1178
+ }
1179
+
1180
+ if (!RARRAY(shadow->curr_T)->len) {
1181
+ //%% hook_end_step();
1182
+ break; //# out of main loop
1183
+ }
1184
+
1185
+ EACH_COMP_DO(shadow->curr_T) {
1186
+ //%% hook_begin_eval_events(comp);
1187
+ if (eval_events(comp_shdw, shadow))
1188
+ rb_ary_push(shadow->active_E, comp);
1189
+ //%% hook_end_eval_events(comp);
1190
+ }
1191
+
1192
+ //# Export new event values.
1193
+ EACH_COMP_DO(shadow->active_E) {
1194
+ SWAP_VALUE(comp_shdw->event_values, comp_shdw->next_event_values);
1195
+ //%% hook_export_events(comp, comp_shdw->event_values);
1196
+ }
1197
+ SWAP_VALUE(shadow->active_E, shadow->prev_active_E);
1198
+ assert(RARRAY(shadow->active_E)->len == 0);
1199
+
1200
+ //%% hook_enter_eval_phase();
1201
+ EACH_COMP_DO(shadow->curr_T) {
1202
+ //%% hook_begin_eval_resets(comp);
1203
+ if (eval_continuous_resets(comp_shdw, shadow))
1204
+ rb_ary_push(shadow->curr_CR, comp);
1205
+ eval_constant_resets(comp_shdw, shadow);
1206
+ eval_port_connects(comp_shdw, shadow);
1207
+ //%% hook_end_eval_resets(comp);
1208
+
1209
+ if (RTEST(cur_actions(comp_shdw)))
1210
+ rb_ary_push(shadow->curr_A, comp);
1211
+
1212
+ if (RTEST(cur_posts(comp_shdw)))
1213
+ rb_ary_push(shadow->curr_P, comp);
1214
+ }
1215
+ //%% hook_leave_eval_phase();
1216
+
1217
+ //%% hook_enter_action_phase();
1218
+ EACH_COMP_DO(shadow->curr_A) {
1219
+ do_actions(comp_shdw, cur_actions(comp_shdw), shadow);
1220
+ }
1221
+ RARRAY(shadow->curr_A)->len = 0;
1222
+ //%% hook_leave_action_phase();
1223
+
1224
+ //%% hook_begin_parallel_assign();
1225
+ did_reset = 0;
1226
+ EACH_COMP_DO(shadow->curr_CR) {
1227
+ did_reset = assign_new_cont_values(comp_shdw) || did_reset;
1228
+ }
1229
+ RARRAY(shadow->curr_CR)->len = 0;
1230
+ did_reset = assign_new_constant_values(shadow) || did_reset;
1231
+ did_reset = assign_new_links(shadow) || did_reset;
1232
+ did_reset = assign_new_ports(shadow) || did_reset;
1233
+ //%% hook_end_parallel_assign();
1234
+
1235
+ //%% hook_enter_post_phase();
1236
+ EACH_COMP_DO(shadow->curr_P) {
1237
+ do_actions(comp_shdw, cur_posts(comp_shdw), shadow);
1238
+ }
1239
+ RARRAY(shadow->curr_P)->len = 0;
1240
+ //%% hook_leave_post_phase();
1241
+
1242
+ EACH_COMP_DO(shadow->curr_T) {
1243
+ finish_trans(comp_shdw, shadow);
1244
+ }
1245
+
1246
+ if (did_reset || 1)
1247
+ shadow->d_tick++;
1248
+ //## replace "1" with "some comp entered new
1249
+ //## state with new alg. eqs"
1250
+
1251
+ EACH_COMP_DO(shadow->curr_T) {
1252
+ check_strict(comp_shdw);
1253
+ //## optimize: only keep comps with var->ck_strict on this list
1254
+ //## option to skip this check
1255
+ }
1256
+
1257
+ //# Check for zeno problem.
1258
+ if (shadow->zeno_limit >= 0) {
1259
+ shadow->zeno_counter++;
1260
+ if (shadow->zeno_counter > shadow->zeno_limit)
1261
+ rb_funcall(shadow->self, #{declare_symbol :step_zeno}, 0);
1262
+ }
1263
+
1264
+ EACH_COMP_DO(shadow->curr_T) {
1265
+ if (comp_shdw->state == ExitState)
1266
+ remove_comp(comp, shadow->curr_T, shadow);
1267
+ else
1268
+ move_comp(comp, shadow->curr_T, shadow->awake);
1269
+ }
1270
+ assert(RARRAY(shadow->curr_T)->len == 0);
1271
+ assert(RARRAY(shadow->prev_awake)->len == 0);
1272
+
1273
+ //# Clear event values.
1274
+ EACH_COMP_DO(shadow->prev_active_E) {
1275
+ rb_mem_clear(RARRAY(comp_shdw->event_values)->ptr,
1276
+ RARRAY(comp_shdw->event_values)->len);
1277
+ }
1278
+ RARRAY(shadow->prev_active_E)->len = 0;
1279
+
1280
+ //%% hook_end_step();
1281
+ }
1282
+
1283
+ move_all_comps(shadow->strict_sleep, shadow->awake);
1284
+
1285
+ //%% hook_end();
1286
+ shadow->discrete_step = 0;
1287
+ shadow->zeno_counter = 0;
1288
+ }
1289
+
1290
+ # only call this when all defs have been added
1291
+ def parent.to_s
1292
+ @cached_output ||= super
1293
+ end
1294
+ end
1295
+
1296
+ hook = /\bhook_\w+/
1297
+ world_classes = World.subclasses + [World]
1298
+ hooks = Hash.new {|h,cl| h[cl] = cl.instance_methods(true).grep(hook).sort}
1299
+ hooks[World.superclass] = nil
1300
+ known_hooks = nil
1301
+
1302
+ world_classes.each do |cl|
1303
+ cl_hooks = hooks[cl]
1304
+ next if hooks[cl.superclass] == hooks[cl]
1305
+
1306
+ cl.class_eval do
1307
+ shadow_library_source_file.include(Component.shadow_library_include_file)
1308
+
1309
+ if (instance_methods(false) + protected_instance_methods(false) +
1310
+ private_instance_methods(false)).include?("step_discrete")
1311
+ warn "Redefining step_discrete in #{self}"
1312
+ end
1313
+
1314
+ meth = define_c_method(:step_discrete, &discrete_step_definer)
1315
+ private :step_discrete
1316
+
1317
+ before_commit do
1318
+ # at this point, we know the file is complete
1319
+ file_str = meth.parent.to_s
1320
+
1321
+ known_hooks ||= file_str.scan(hook)
1322
+ unknown_hooks = cl_hooks - known_hooks
1323
+
1324
+ unless unknown_hooks.empty?
1325
+ warn "Unknown hooks:\n #{unknown_hooks.join("\n ")}"
1326
+ end
1327
+
1328
+ hook_pat =
1329
+ /\/\/%%[ \t]*(#{cl_hooks.join("|")})\(((?:.|\n[ \t]*\/\/%%)*)\)/
1330
+ file_str.gsub!(hook_pat) do
1331
+ hook = $1
1332
+ argstr = $2.gsub(/\/\/%%/, "")
1333
+ args = argstr.split(/,\s+/)
1334
+ args.each {|arg| arg.gsub(/\/\/.*$/, "")}
1335
+ # crude parser--no ", " within args, but may be multiline
1336
+ # and may have "//" comments, which can be used to extend an arg
1337
+ # across lines.
1338
+ args.unshift(args.size)
1339
+ ## enclose the following in if(shadow->hook) {...}
1340
+ %{rb_funcall(shadow->self, #{meth.declare_symbol hook},
1341
+ #{args.join(", ")})}
1342
+ end
1343
+ end
1344
+ end
1345
+ end
1346
+
1347
+ end # class World
1348
+
1349
+ ### move this to component-gen.rb
1350
+ class Component
1351
+ shadow_library_include_file.include(World.shadow_library_include_file)
1352
+ shadow_attr_reader :world => [World]
1353
+ ## :nonpersistent -- see __restore__world__refs
1354
+
1355
+ define_c_method :__set__world do
1356
+ ## possible to do this by shadow_attr_writer, and
1357
+ ## post-commit alias and remove_method and protected?
1358
+ arguments :world
1359
+ world_ssn = World.shadow_struct_name
1360
+ body %{
1361
+ if (world != Qnil) {
1362
+ Data_Get_Struct(world, #{world_ssn}, shadow->world);
1363
+ } else
1364
+ shadow->world = 0;
1365
+ }
1366
+ end
1367
+ protected :__set__world
1368
+ end
1369
+
1370
+ end # module RedShift