redshift 1.3.15
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.
- data/.gitignore +8 -0
- data/README +5 -0
- data/RELEASE-NOTES +455 -0
- data/TODO +431 -0
- data/bench/alg-state.rb +61 -0
- data/bench/bench +26 -0
- data/bench/bench.rb +10 -0
- data/bench/continuous.rb +76 -0
- data/bench/diff-bench +86 -0
- data/bench/discrete.rb +101 -0
- data/bench/euler.rb +50 -0
- data/bench/formula.rb +78 -0
- data/bench/half-strict.rb +103 -0
- data/bench/inertness.rb +116 -0
- data/bench/queue.rb +92 -0
- data/bench/run +66 -0
- data/bench/simple.rb +74 -0
- data/bench/strictness.rb +86 -0
- data/examples/ball-tkar.rb +72 -0
- data/examples/ball.rb +123 -0
- data/examples/collide.rb +70 -0
- data/examples/connect-parallel.rb +48 -0
- data/examples/connect.rb +109 -0
- data/examples/constants.rb +27 -0
- data/examples/delay.rb +80 -0
- data/examples/derivative.rb +77 -0
- data/examples/euler.rb +46 -0
- data/examples/external-lib.rb +33 -0
- data/examples/guard-debugger.rb +77 -0
- data/examples/lotka-volterra.rb +33 -0
- data/examples/persist-ball.rb +68 -0
- data/examples/pid.rb +87 -0
- data/examples/ports.rb +60 -0
- data/examples/queue.rb +56 -0
- data/examples/queue2.rb +98 -0
- data/examples/reset-with-event-val.rb +28 -0
- data/examples/scheduler.rb +104 -0
- data/examples/set-dest.rb +23 -0
- data/examples/simulink/README +1 -0
- data/examples/simulink/delay.mdl +827 -0
- data/examples/simulink/derivative.mdl +655 -0
- data/examples/step-discrete-profiler.rb +103 -0
- data/examples/subsystem.rb +109 -0
- data/examples/sync-deadlock.rb +32 -0
- data/examples/sync-queue.rb +91 -0
- data/examples/sync-retry.rb +20 -0
- data/examples/sync.rb +51 -0
- data/examples/thermostat.rb +53 -0
- data/examples/zeno.rb +53 -0
- data/lib/accessible-index.rb +47 -0
- data/lib/redshift.rb +1 -0
- data/lib/redshift/component.rb +412 -0
- data/lib/redshift/meta.rb +183 -0
- data/lib/redshift/mixins/zeno-debugger.rb +69 -0
- data/lib/redshift/port.rb +57 -0
- data/lib/redshift/queue.rb +104 -0
- data/lib/redshift/redshift.rb +111 -0
- data/lib/redshift/state.rb +31 -0
- data/lib/redshift/syntax.rb +558 -0
- data/lib/redshift/target/c.rb +37 -0
- data/lib/redshift/target/c/component-gen.rb +1303 -0
- data/lib/redshift/target/c/flow-gen.rb +325 -0
- data/lib/redshift/target/c/flow/algebraic.rb +85 -0
- data/lib/redshift/target/c/flow/buffer.rb +74 -0
- data/lib/redshift/target/c/flow/delay.rb +203 -0
- data/lib/redshift/target/c/flow/derivative.rb +101 -0
- data/lib/redshift/target/c/flow/euler.rb +67 -0
- data/lib/redshift/target/c/flow/expr.rb +113 -0
- data/lib/redshift/target/c/flow/rk4.rb +80 -0
- data/lib/redshift/target/c/library.rb +85 -0
- data/lib/redshift/target/c/world-gen.rb +1370 -0
- data/lib/redshift/target/spec.rb +34 -0
- data/lib/redshift/world.rb +300 -0
- data/rakefile +37 -0
- data/test/test.rb +52 -0
- data/test/test_buffer.rb +58 -0
- data/test/test_connect.rb +242 -0
- data/test/test_connect_parallel.rb +47 -0
- data/test/test_connect_strict.rb +135 -0
- data/test/test_constant.rb +74 -0
- data/test/test_delay.rb +145 -0
- data/test/test_derivative.rb +48 -0
- data/test/test_discrete.rb +592 -0
- data/test/test_discrete_isolated.rb +92 -0
- data/test/test_exit.rb +59 -0
- data/test/test_flow.rb +200 -0
- data/test/test_flow_link.rb +288 -0
- data/test/test_flow_sub.rb +100 -0
- data/test/test_flow_trans.rb +292 -0
- data/test/test_inherit.rb +127 -0
- data/test/test_inherit_event.rb +74 -0
- data/test/test_inherit_flow.rb +139 -0
- data/test/test_inherit_link.rb +65 -0
- data/test/test_inherit_setup.rb +56 -0
- data/test/test_inherit_state.rb +66 -0
- data/test/test_inherit_transition.rb +168 -0
- data/test/test_numerics.rb +34 -0
- data/test/test_queue.rb +90 -0
- data/test/test_queue_alone.rb +115 -0
- data/test/test_reset.rb +209 -0
- data/test/test_setup.rb +119 -0
- data/test/test_strict_continuity.rb +410 -0
- data/test/test_strict_reset_error.rb +30 -0
- data/test/test_strictness_error.rb +32 -0
- data/test/test_sync.rb +185 -0
- data/test/test_world.rb +328 -0
- 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
|