2 bridge-tcl bridge-tk bridge-blt
6 This family of components implements a bridge between the C++ SID
7 API and Tcl, in an embedded Tcl/Tk/Tk+blt 8.0 interpreter.
9 * Pins: !event !event-control (+BRIDGED)
10 * Attributes: load! eval! (+BRIDGED)
12 * Accessors: (BRIDGED)
13 * Relationships: (BRIDGED)
15 * Library: libtclapi.la
16 * Symbol name: tcl_component_library
22 * As this family of components is just a bridge, the nature of
23 modelling performed is up to the script on the other side of the
24 bridge. This component merely funnels SID API calls between the
25 outer C++ system and each bridge component's isolated embedded tcl
32 You must configure the embedded Tcl interpreter with the
33 Tcl scripting code that will receive bridged C++ SID API calls.
34 This can be done in two ways. First, if the "load!" attribute is
35 written to, the value is interpreted as a file name, and loaded
36 into the Tcl interpreter as if with the Tcl "source" command.
37 This file may contain procedure definitions and any Tcl code to be
38 evaluated right away. Second, if the "eval!" attribute is written
39 to, the value is interpreted as a Tcl expression as if the
40 Tcl_Eval() function had been used.
42 A "bridge-tk" type component is automatically initialized with the
43 usual bindings to the Tk windowing toolkit. A "bridge-blt" type
44 component, where available, includes the same Tk bindings, in
45 addition to the usual bindings to the BLT Tcl extension library.
49 The embedded Tcl interpreter requires regular-event polling in
50 order to operate, especially if the tk or tk+blt extensions are in
51 use. Whenever the "!event" input pin is driven, the
52 Tcl_DoOneEvent() function is called repeatedly for all pending Tcl
55 In response, the "!event-control" output pin is driven with a
56 number between 1 and 1000. The number represents the component's
57 suggestion about the time interval to the next "!event" signal,
58 and is meant to be compatible with the "sid-sched-*" components'
59 "NNN-control" inputs. This way, the Tcl bridge component attempts
60 to adaptively regulate its own event polling rate, balancing good
61 response time in busy periods and low overhead during idle
66 With only the exceptions noted above, all incoming C++ SID API
67 calls are bridged by making appropriate calls to an embedded Tcl
68 interpreter. One Tcl procedure call is made per C++ call. Types
69 and function names are mapped as specified in the Incoming sid API
72 The invoked Tcl procedure may perform any necessary processing and
73 return a value. It may make further SID API calls outward to
74 other components through the symmetrical Tcl-to-C++ bridging
75 described in the Outgoing sid API calls section.
77 Tcl interpreter errors are caught during the bridging process. In
78 case the interpreter fails to run the appropriate Tcl procedure to
79 completion, a "TCL ERROR" message is printed to stderr, and some
80 error-suggesting return value is made up for completing the C++
81 call. This situation is analogous to a C++ component throwing an
82 exception during its execution of an incoming SID API call, though
83 in the pure C++ case, uncaught exceptions cause the SID process to
88 This component bridges an API. Any conventions supported by the
89 loaded script on the Tcl side will be supported on the C++ side
90 of the bridge. The bridge does not implement any SID conventions
97 * As suggested in the "Event handling" behavior section above, this
98 component performs best if the "!event" and "!event-control" pins
99 are connected to a scheduler. If the bridge component is to carry
100 out any work, it is necessary to load Tcl script fragments into
101 it. Here is a script fragment that does both.
103 new bridge-tcl tracer
104 new sid-sched-host sched
105 set tracer load! "/path/my-component.tcl"
106 connect-pin sched 0-event -> tracer !event
107 connect-pin sched 0-control <- tracer !event-control
109 * A more sophisticated way to use a bridge component is to
110 associate SID triggerpoint hits with scripted actions. For example,
111 the following fragment activates a triggerpoint on a register of a
112 peripheral, and prints a message whenever it hits. Note how the Tcl
113 script is fed in piece by piece using the "eval!" attribute.
115 new bridge-tcl watcher
117 # Configure bare minimum tcl code to make an input pin and
118 # respond to it being driven. Note how find_pin does not
119 # check the pin name, so any name will be accepted in the
120 # later connect-pin line.
121 set watcher eval! "set p [sid::pin::new]"
122 set watcher eval! "proc find_pin {name} {global p ; return $p}"
123 set watcher eval! "proc driven_h4 {pin value} {puts \"triggerpoint hit v=$value!\"}"
124 # triggerpoint: watch victim component's register "r0" for value 0xAA
125 connect-pin victim watch:r0:value:0xAA -> watcher anyname
129 * The bridge-tcl and bridge-tk components are available on all
130 platforms. The bridge-blt component is available only if the BLT
131 Tcl extension library was compiled into this component.
133 * Each instance of a "bridge-tk" or "bridge-blt" component creates a
134 separate new top-level tk window.
137 * SID interface reference
141 Note that this list includes only those low level interfaces that
142 are actually provided by the bridge component. In order to act
143 transparent, these are excluded from the pin_names and
144 attribute_names inquiry functions. All visible low level
145 interfaces actually come from the Tcl scripting code loaded into
149 - !event | input | any | event handling
150 - !event-control | output | 1-1000 | event handling
153 - load! | | file name | n/a | configuration
154 - eval! | | string | n/a | configuration
158 Theory of operation for tcl-bridge component
159 --------------------------------------------
161 A tcl-bridge component is a shell that hooks all sid API calls to an
162 embedded tcl interpreter so that they can be handled as tcl procedure
163 calls. In addition, sid API calls are exposed to that interpreter, so
164 the tcl procedures can call back out to the C++ system. With these two
165 capabilities, a user-provided tcl package may *become* a first class
168 Objects such as bus, component, and pin pointers may be passed through
169 tcl scripts safely, because the bridging calls represent these as
170 unique strings, and convert them back to C++ pointers automatically. Any
171 pointers seen through incoming call arguments, or outgoing call return
172 values, are transparently converted into unique long-lived opaque
173 strings. This way, C++ pointers can safely pass through the tcl
174 bridge in both directions.
176 Unlike C++ components, tcl scripts that run in a tcl-bridge do not
177 have access to the sidutil:: group of utility classes. This means
178 that only low level operations are directly provided, and sidutil::
179 abstractions would need to be rewritten (if needed) in tcl.
182 Incoming sid API calls
183 ----------------------
185 Almost all incoming sid API calls are passed through verbatim to the
186 embedded tcl interpreter. (Exceptions are parameterized and noted
187 below.) Plain types are mapped according to the table below: C++
188 object to tcl for arguments, and tcl to C++ for return values. If tcl
189 procedures by the appropriate names are not loaded into the
190 interpreter by the time they are invoked from another sid component,
191 a "TCL ERROR" message is printed to cerr, and a function-specific
192 error indication is returned.
194 Calls belonging to sid::pin and sid::bus are similarly mapped to
195 tcl procedure calls. The C++ pin/bus object on which they are called
196 is passed to the procedures as an extra argument. (C++ pin/bus
197 objects may be constructed for a tcl component through special
198 callback functions, listed below.)
200 Functions with multiple outputs, like the sid::bus::read reference
201 arguments, map to tcl procedures returning a list with the mapped C++
202 return type as first element, and the output reference argument as
209 vector<string> list of strings
210 component,bus,pin pointer opaque string
211 {little,big,host}_int_{1,2,4,8} numeric integer - care with 64-bit ints!
212 component::status string: "ok", "bad_value", "not_found"
213 bus::status string: "ok", "misaligned", "unmapped",
214 "unpermitted", "delayed"
215 vector<component*> list of opaque strings
216 vector<pin*> list of opaque strings
220 incoming C++ call outgoing tcl call
224 attribute_names() attribute_names
225 attribute_names(category) attribute_names_in_category $category
226 attribute_value(name) attribute_value $name
227 set_attribute_value(name,value) set_attribute_value $name $value
229 find_pin(name) find_pin $name
230 connect_pin(name, pin) connect_pin $name $pin
231 disconnect_pin(name, pin) disconnect_pin $name $pin
232 connected_pins(name) connected_pins $name
234 find_bus(name) find_bus $name
235 accessor_names accessor_names
236 connect_accessor(name,bus) connect_accessor $name $bus
237 disconnect_accessor(name,bus) disconnect_accessor $name $bus
238 connected_bus(name) connected_bus $name
239 relationship_names() relationship_names
240 relate(rel,comp) relate $rel $comp
241 unrelate(rel,comp) unrelate $rel $comp
242 related_components(rel) related_components $rel
246 driven(value) driven_h4 $pin $value
248 -- in sid::bus, for host_int_4 address and {big,little}_int_Y data types
250 read(address,data) read_h4_{l,b}Y $address ** return [list $status $data] **
251 write(address,data) write_h4_{l,b}Y $address $data
254 Outgoing sid API calls
255 ----------------------
257 Once a tcl program is loaded into the interpreter, it is able to make
258 outgoing sid API calls, not merely respond to incoming ones. All sid
259 API functions are exposed to tcl as procedure hooks, in a very
260 symmetric way to the incoming calls. Simply, each function in the
261 incoming set has a shadow: "sid::component::FUNCTION",
262 "sid::pin::FUNCTION" or "sid::bus::FUNCTION", as appropriate. Each
263 outgoing procedure takes a receiver handle (the same opaque string
264 passed in an incoming call) as its first argument.
266 There is no checking that would prevent an outgoing sid API call from
267 becoming recursive and referring to the originating component, either
268 directly or indirectly. As for all other components, infinite
269 recursion prevention is the responsibility of the component author.
274 attribute_value $name sid::component::attribute_value $component $name
275 driven_h4 $pin $value sid::pin::driven_h4 $pin $value
279 There are some special outgoing functions that function as
280 constructors for local object handles.
282 sid::component::this returns an opaque string handle to this component
283 sid::pin::new returns an opaque string handle to a new private C++ pin,
284 usable as a return value to `find_pin'
285 sid::bus::new returns an opaque string handle to a new private C++ bus,
286 usable as a return value to `find_bus'