Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | \ ========== Copyright Header Begin ========================================== |
2 | \ | |
3 | \ Hypervisor Software File: devtree.fth | |
4 | \ | |
5 | \ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | \ | |
7 | \ - Do no alter or remove copyright notices | |
8 | \ | |
9 | \ - Redistribution and use of this software in source and binary forms, with | |
10 | \ or without modification, are permitted provided that the following | |
11 | \ conditions are met: | |
12 | \ | |
13 | \ - Redistribution of source code must retain the above copyright notice, | |
14 | \ this list of conditions and the following disclaimer. | |
15 | \ | |
16 | \ - Redistribution in binary form must reproduce the above copyright notice, | |
17 | \ this list of conditions and the following disclaimer in the | |
18 | \ documentation and/or other materials provided with the distribution. | |
19 | \ | |
20 | \ Neither the name of Sun Microsystems, Inc. or the names of contributors | |
21 | \ may be used to endorse or promote products derived from this software | |
22 | \ without specific prior written permission. | |
23 | \ | |
24 | \ This software is provided "AS IS," without a warranty of any kind. | |
25 | \ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
26 | \ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
27 | \ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
28 | \ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
29 | \ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
30 | \ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
31 | \ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
32 | \ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
33 | \ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
34 | \ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
35 | \ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
36 | \ | |
37 | \ You acknowledge that this software is not designed, licensed or | |
38 | \ intended for use in the design, construction, operation or maintenance of | |
39 | \ any nuclear facility. | |
40 | \ | |
41 | \ ========== Copyright Header End ============================================ | |
42 | id: @(#)devtree.fth 3.23 06/02/16 19:19:51 | |
43 | purpose: | |
44 | copyright: Copyright 2006 Sun Microsystems, Inc. All Rights Reserved | |
45 | copyright: Use is subject to license terms. | |
46 | ||
47 | headerless | |
48 | ||
49 | headers | |
50 | : get ( acf -- value ) 0 perform-action ; | |
51 | : set ( value acf -- ) 1 perform-action ; | |
52 | : decode ( value acf -- adr len ) 3 perform-action ; | |
53 | : encode ( adr len acf -- true | value false ) | |
54 | 4 ['] perform-action catch if | |
55 | 2drop 2drop true | |
56 | else | |
57 | false | |
58 | then | |
59 | ; | |
60 | ||
61 | \ TODO | |
62 | \ Don't use the system search order; use a private stack | |
63 | \ $find searches through the private stack | |
64 | \ Change names back from "regprop" to "reg", etc. | |
65 | \ Either implement a true breadth-first search or don't specify it. | |
66 | ||
67 | 2 actions | |
68 | action: drop context token@ ; | |
69 | action: drop context token! definitions ; | |
70 | create current-device use-actions | |
71 | ||
72 | : >node-offset ( apf -- addr ) @ current-device >body >user + ; | |
73 | ||
74 | 1 actions | |
75 | action: >node-offset ; | |
76 | ||
77 | transient | |
78 | ||
79 | : (ufield) \ name ( offset size -- offset' ) | |
80 | create over , + | |
81 | ; | |
82 | ||
83 | : ufield \ name ( offset size -- offset' ) | |
84 | (ufield) use-actions | |
85 | ; | |
86 | ||
87 | resident | |
88 | ||
89 | 3 actions | |
90 | action: >node-offset token@ execute ; | |
91 | action: >node-offset token! ; | |
92 | action: >node-offset ; | |
93 | ||
94 | transient | |
95 | : node-defer \ name ( offset -- offset' ) | |
96 | /token (ufield) use-actions | |
97 | ; | |
98 | resident | |
99 | ||
100 | \ Notes for a more abstract searching mechanism: | |
101 | \ Instead of the child and peer links in the device node, packages | |
102 | \ with children have "search", "create", and "enumerate" methods. | |
103 | \ To search a level, call that package's search method. Those | |
104 | \ methods probably need to work from a phandle, not an ihandle. | |
105 | ||
106 | \ The 'check-user-size' below enables user space to grow on demand. | |
107 | ||
108 | : unaligned-ualloc ( size -- user# ) | |
109 | check-user-size #user @ swap #user +! ( user# ) | |
110 | ; | |
111 | ||
112 | struct ( devnode ) | |
113 | /link #threads * ufield 'threads \ Package methods | |
114 | dup \ These fields will be "ualloc"ed | |
115 | /token ufield 'child \ Pointer to first child | |
116 | /token ufield 'peer \ Pointer to next peer | |
117 | /token ufield 'properties \ Pointer to properties vocabulary | |
118 | /n ufield '#adr-cells \ Size of a parent address | |
119 | /n ufield '#buffers | |
120 | /n ufield '#values | |
121 | /token ufield 'values | |
122 | /n ufield support-node? \ is this a support node? | |
123 | /n ufield inherit-node-flags? \ inherit parent props? | |
124 | node-defer (encode-unit) \ encode-unit method | |
125 | node-defer (decode-unit) \ decode-unit method | |
126 | ( starting-offset ending-offset ) swap - ( size-to-ualloc ) | |
127 | constant /devnode-extra | |
128 | ||
129 | headers | |
130 | : >parent ( node -- parent-node ) >voc-link link@ ; | |
131 | ||
132 | : push-package ( phandle -- ) also execute definitions ; | |
133 | : pop-package ( -- ) previous definitions ; | |
134 | : push-device ( acf -- ) to current-device ; | |
135 | ||
136 | : pop-device ( -- ) | |
137 | current-device >parent ( parent-voc ) | |
138 | non-null? if push-device then | |
139 | ; | |
140 | ||
141 | \ Each package instance has its own private data storage area. | |
142 | \ The data creation words "value", "variable", and "buffer:", | |
143 | \ when used during compilation of a package, allocate memory | |
144 | \ relative to a base pointer. The package definition includes the | |
145 | \ initial values for the words created with "value" and "variable". | |
146 | \ When a package instance is created, memory is allocated for the | |
147 | \ package's data and the portion used for values and variables is | |
148 | \ initialized from the values stored in the package definition. | |
149 | \ | |
150 | \ While the package is being defined (i.e. its code is being compiled), | |
151 | \ a "dummy" instance is created with space for data, so that | |
152 | \ data words may be used as soon as they are created. The "dummy" | |
153 | \ instance data area is given a "generous" default size (for 100 * cellsize | |
154 | \ bytes of initialized data, 700 * cellsize for buffers). | |
155 | \ Hopefully this won't be exceeded. | |
156 | ||
157 | headerless | |
158 | variable package-level package-level off | |
159 | variable next-is-instance next-is-instance off | |
160 | headers | |
161 | variable instance-mode instance-mode off | |
162 | headerless | |
163 | : instance? ( -- flag ) | |
164 | ||
165 | \ \ Debugging code. Keep this in until we have "sanitized" the drivers. | |
166 | \ package-level @ 0<> next-is-instance @ 0= and instance-mode @ and if | |
167 | \ ." Instance problem " where ??cr | |
168 | \ then | |
169 | ||
170 | package-level @ 0<> next-is-instance @ instance-mode @ or and | |
171 | next-is-instance off | |
172 | ; | |
173 | headers | |
174 | : instance ( -- ) next-is-instance on ; | |
175 | headerless | |
176 | ||
177 | \ Now in machine code in obp/os/bootprom/sparc/instance.fth | |
178 | \ : >instance-data ( pfa -- adr ) @ my-self + ; | |
179 | ||
180 | : value#, ( size -- adr ) | |
181 | '#values @ dup , ( size offset ) | |
182 | tuck + '#values ! ( offset ) | |
183 | my-self + ( adr ) | |
184 | ; | |
185 | ||
186 | headers | |
187 | overload: value \ name ( initial-value -- ) | |
188 | header noop \ Will patch with (value) | |
189 | ; | |
190 | headerless | |
191 | 3 actions | |
192 | action: >instance-data @ ; | |
193 | action: >instance-data ! ; | |
194 | action: >instance-data ; | |
195 | ||
196 | : (value) ( initial-value -- ) | |
197 | instance? if | |
198 | create-cf use-actions /n value#, | |
199 | else | |
200 | value-cf /n user#, | |
201 | then ( value adr ) | |
202 | ! | |
203 | ; patch (value) noop value | |
204 | ||
205 | \ Create fields which are present in every instance record. | |
206 | \ "fixed instance value" | |
207 | ||
208 | headers | |
209 | transient | |
210 | : fibuf: \ name ( offset -- offset' ) | |
211 | create -1 na+ dup , ( offset' ) | |
212 | use-actions | |
213 | ; | |
214 | : fival: \ name ( offset -- offset' ) | |
215 | create dup , na1+ ( offset' ) | |
216 | use-actions | |
217 | ; | |
218 | resident | |
219 | ||
220 | headers | |
221 | overload: buffer: \ name ( size -- ) | |
222 | header noop \ Will patch with (buffer:) | |
223 | ; | |
224 | ||
225 | 3 actions | |
226 | action: >instance-data ; | |
227 | action: >instance-data ! ; | |
228 | action: >instance-data ; | |
229 | ||
230 | headerless | |
231 | overload: (buffer:) ( #bytes -- ) | |
232 | instance? if | |
233 | create-cf | |
234 | \ The address computation should use "#dalign round-up", but | |
235 | \ #dalign (8) is defined later, in the "allocator" vocabulary. | |
236 | '#buffers @ swap 8 round-up - dup , '#buffers ! use-actions | |
237 | else | |
238 | (buffer:) | |
239 | then | |
240 | ; patch (buffer:) noop buffer: | |
241 | ||
242 | headers | |
243 | overload: variable \ name ( -- ) | |
244 | header noop \ Will patch with (variable) | |
245 | ; | |
246 | ||
247 | 3 actions | |
248 | action: >instance-data ; | |
249 | action: >instance-data ! ; | |
250 | action: >instance-data ; | |
251 | ||
252 | headerless | |
253 | : (variable) ( -- ) | |
254 | instance? if | |
255 | create-cf use-actions 0 /n value#, else user-cf 0 /n user#, | |
256 | then | |
257 | ! | |
258 | ; patch (variable) noop variable | |
259 | ||
260 | headers | |
261 | overload: defer \ name ( -- ) | |
262 | header noop \ Will patch with (defer) | |
263 | ; | |
264 | ||
265 | 3 actions | |
266 | action: >instance-data token@ execute ; | |
267 | action: >instance-data token! ; | |
268 | action: >instance-data token@ ; | |
269 | ||
270 | headerless | |
271 | : (defer) ( -- ) | |
272 | instance? if | |
273 | create-cf ['] crash /token ( value data-size ) | |
274 | use-actions value#, | |
275 | else | |
276 | defer-cf ['] crash /token ( value data-size ) | |
277 | user#, | |
278 | then ( value adr ) | |
279 | token! | |
280 | ; patch (defer) noop defer | |
281 | ||
282 | headers | |
283 | \ Instance values that are automatically created for every package instance. | |
284 | ||
285 | 0 | |
286 | fival: my-adr0 \ F: First component of device probe address | |
287 | fival: my-adr1 \ F: Intermediate component of device probe address | |
288 | fival: my-adr2 \ F: Intermediate component of device probe address | |
289 | fival: my-space \ F: Last component of device probe address | |
290 | fival: frame-buffer-adr \ F: Frame buffer address. Strictly speaking, this | |
291 | \ should not be in every package, but we put it | |
292 | \ here as a work-around for some old CG6 FCode | |
293 | \ drivers whose selftest routines use frame-buffer-adr | |
294 | \ for diagnostics mappings. If frame-buffer-adr is | |
295 | \ global, that would cause dual-cg6 systems to break. | |
296 | fival: my-termemu | |
297 | fival: interposed? \ Was this instance interposed? | |
298 | headerless | |
299 | constant #fixed-vals | |
300 | headers | |
301 | ||
302 | 0 | |
303 | fibuf: my-voc \ Package definition (code) for this instance | |
304 | fibuf: my-parent \ Current instance just before this one was created | |
305 | fibuf: my-args-adr \ Argument string - base address | |
306 | fibuf: my-args-len \ Argument string - length | |
307 | fibuf: my-unit-3 \ Fourth component of device instance address | |
308 | fibuf: my-unit-2 \ Third component of device instance address | |
309 | fibuf: my-unit-1 \ Second component of device instance address | |
310 | fibuf: my-unit-low \ First component of device instance address | |
311 | ||
312 | headerless | |
313 | constant #fixed-bufs | |
314 | ||
315 | headers | |
316 | : my-args ( -- adr len ) my-args-adr my-args-len ; | |
317 | ||
318 | headerless | |
319 | : allocate-instance ( value-size variable-size -- ) | |
320 | \ Allocate instance record | |
321 | my-self >r ( val-size var-size ) | |
322 | tuck + alloc-mem ( var-size base-adr ) | |
323 | + is my-self ( ) | |
324 | ||
325 | \ Set the fixed fields | |
326 | r> to my-parent ( ) | |
327 | current-device to my-voc ( ) | |
328 | ||
329 | 0 to my-args-len 0 to my-args-adr ( ) \ May be changed later | |
330 | 0 to interposed? ( ) | |
331 | 0 to my-unit-low 0 to my-unit-1 ( ) | |
332 | 0 to my-unit-2 0 to my-unit-3 ( ) | |
333 | ; | |
334 | ||
335 | : initial-values ( -- adr ) 'values token@ ; | |
336 | ||
337 | \ Returns the address of the initial value of the named instance data. | |
338 | : (initial-addr) ( adr -- adr' ) my-self - initial-values + ; | |
339 | : initial-addr \ name ( -- addr ) | |
340 | [compile] addr | |
341 | state @ if compile (initial-addr) else (initial-addr) then | |
342 | ; immediate | |
343 | ||
344 | headers | |
345 | : copy-args ( args-adr,len -- ) | |
346 | dup if | |
347 | dup alloc-mem to my-args-adr ( args-adr,len ) | |
348 | to my-args-len ( args-adr ) | |
349 | my-args-adr my-args-len move ( ) | |
350 | else | |
351 | 2drop | |
352 | then | |
353 | ; | |
354 | ||
355 | \ my-self points to a position in the middle of the instance record. | |
356 | \ Initialized data ("values") is at positive offsets from my-self, | |
357 | \ and uninitialized data ("variables" and "buffers") is at negative offsets. | |
358 | : new-instance ( args-adr args-len -- ) | |
359 | '#values @ '#buffers @ negate allocate-instance | |
360 | ||
361 | \ Copy in the initialized data | |
362 | initial-values my-self '#values @ move ( args-adr args-len ) | |
363 | ||
364 | copy-args | |
365 | ; | |
366 | ||
367 | headerless | |
368 | : deallocate-instance ( value-size variabled-size -- ) | |
369 | my-args-len if my-args-adr my-args-len free-mem then | |
370 | my-self my-parent is my-self ( val-size var-size self ) | |
371 | over - ( val-size var-size base-adr ) | |
372 | -rot + free-mem ( ) | |
373 | ; | |
374 | ||
375 | \ Destroy instance has the side effect of setting my-self to the parent | |
376 | \ of the node that is being destroyed. This prevents my-self from referring | |
377 | \ to a non-existent instance. | |
378 | ||
379 | headers | |
380 | : destroy-instance ( -- ) | |
381 | also my-voc execute ( ) | |
382 | '#values @ '#buffers @ negate ( value-size variable-size ) | |
383 | previous ( value-size variable-size ) | |
384 | deallocate-instance | |
385 | ; | |
386 | ||
387 | headerless | |
388 | \ When creating a package definition, we initialize the buffer | |
389 | \ (unitialized data) allocation pointer and the value (initialized data) | |
390 | \ allocation pointer. | |
391 | ||
392 | \ Size of the buffer that is used as the instance data when the package | |
393 | \ is being created. This allows variables, buffers, and values to be | |
394 | \ used while the package is being created. | |
395 | ||
396 | : initial-sizes ( -- value-size variable-size ) | |
397 | d# 100 /n* d# 700 /n* | |
398 | ; | |
399 | ||
400 | : extend-package ( -- ) | |
401 | next-is-instance off | |
402 | 1 package-level +! initial-sizes allocate-instance | |
403 | ; | |
404 | ||
405 | : allot-package-data ( -- ) | |
406 | acf-align here dup 'values token! '#values @ dup allot erase | |
407 | ; | |
408 | : finish-package-data ( -- ) | |
409 | \ Copy the initialized data into the dictionary and set up the | |
410 | \ pointer to it. | |
411 | '#values @ if allot-package-data then | |
412 | my-self initial-values '#values @ move ( ) | |
413 | ||
414 | initial-addr frame-buffer-adr off | |
415 | initial-addr my-termemu off | |
416 | ||
417 | initial-sizes deallocate-instance ( ) | |
418 | package-level @ 1- 0 max package-level ! | |
419 | ; | |
420 | ||
421 | \ Internal factor used to implement first-child and next-child | |
422 | : set-child? ( link-adr -- flag ) | |
423 | get-token? if push-device true else false then | |
424 | ; | |
425 | ||
426 | \ Interface to searching code in breadth.fth: | |
427 | : first-child ( -- another? ) 'child set-child? ; | |
428 | : next-child ( -- another? ) 'peer pop-device set-child? ; | |
429 | ||
430 | \ Removes the voc-link field from the most-recently-created vocabulary | |
431 | : erase-voc-link ( -- ) | |
432 | voc-link link@ >voc-link link@ voc-link link! | |
433 | /link na1+ negate allot | |
434 | ; | |
435 | ||
436 | \ Creates an unnamed vocabulary | |
437 | : (vocabulary) ( -- ) | |
438 | ['] acf-align is header | |
439 | vocabulary | |
440 | ['] (header) is header | |
441 | ||
442 | erase-voc-link | |
443 | ; | |
444 | ||
445 | : allocate-node-record ( -- ) | |
446 | \ Allocate user (RAM) space for properties, "last" field, children, peers | |
447 | /devnode-extra unaligned-ualloc drop | |
448 | ||
449 | lastacf push-device ( parent's-child-field ) | |
450 | ; | |
451 | : init-properties ( -- ) (vocabulary) lastacf 'properties token! ; | |
452 | ||
453 | headerless | |
454 | ||
455 | \ this was moved from finddev because the encode/decode unit recovery | |
456 | \ mechanism needs it, and in order to only complain once about missing | |
457 | \ methods and to accelerate the device tree parsing these were moved here. | |
458 | ||
459 | 2variable saved-method$ | |
460 | variable saved-method-package | |
461 | defer no-proc ' true is no-proc \ definition requires forward references.. | |
462 | ||
463 | : setup-method$ ( adr len phandle -- adr len phandle ) | |
464 | >r r@ saved-method-package ! ( adr len ) | |
465 | 2dup saved-method$ 2! ( adr len ) | |
466 | r> ( adr len phandle ) | |
467 | ; | |
468 | headers | |
469 | ||
470 | : current-properties ( -- ) 'properties token@ ; | |
471 | ||
472 | : $vexecute? ( adr len voc-acf -- true | ??? false) | |
473 | (search-wordlist) if execute false else true then | |
474 | ; | |
475 | ||
476 | : $vexecute ( adr len voc-acf -- ?? ) $vexecute? drop ; | |
477 | ||
478 | \ Used during compilation (probing), when the search order includes | |
479 | \ the current vocabulary as well as the parent vocabularies. | |
480 | : get-property ( name-adr,len -- true | value-adr,len false ) | |
481 | current-properties $vexecute? | |
482 | ; | |
483 | headerless | |
484 | : #adr-cells ( -- n ) | |
485 | " #address-cells" get-property if 2 else get-encoded-int then | |
486 | ; | |
487 | ||
488 | \ this routine will only execute once per node, unless the device tree | |
489 | \ changes (via cd, device-end or finish-device) it looks up the static | |
490 | \ acf for the encode/decode method substituting the default 2cell form | |
491 | \ and complaining once, if the method does not exist. | |
492 | : (lookup-method) ( ? ? def-acf ptr method$ -- ? ? ) | |
493 | current-device setup-method$ (search-wordlist) if ( ? ? def-acf ptr acf ) | |
494 | >r ( ? ? default-acf ptr ) | |
495 | nip ( ? ? ptr ) | |
496 | else ( ? ? default-acf ptr ) | |
497 | swap >r ( ? ? ptr ) | |
498 | no-proc ( ? ? ptr -2 ) | |
499 | 2 #adr-cells tuck ( ? ? ptr -2 n 2 n ) | |
500 | <> swap 0<> and if throw else drop then ( ? ? ptr ) | |
501 | diagnostic-mode? if ( ? ? ptr ) | |
502 | ??cr ." Notice: " abort-message type cr | |
503 | then ( ? ? ptr ) | |
504 | then ( ? ? ptr ) | |
505 | r> tuck swap ( ? ? acf acf ptr ) | |
506 | set ( ? ? acf ) | |
507 | execute ( ? ? ) | |
508 | ; | |
509 | ||
510 | \ Moved from findev.fth because the device tree depends upon | |
511 | \ encode-unit and decode-unit, and because some cards are missing those | |
512 | \ methods and we have to workaround them this becomes a fundamental part | |
513 | \ of the device tree operation now. | |
514 | ||
515 | create bad-number ," Bad number syntax" | |
516 | : safe->number ( adr len -- n ) $hnumber if bad-number throw then ; | |
517 | ||
518 | headers | |
519 | ||
520 | : parse-int ( adr len -- n ) dup if safe->number else 2drop 0 then ; | |
521 | ||
522 | : parse-2int ( adr len -- address space ) | |
523 | ascii , left-parse-string ( after-str before-str ) | |
524 | parse-int >r ( after-str ) | |
525 | parse-int r> ( address space ) | |
526 | ; | |
527 | ||
528 | headerless | |
529 | ||
530 | : (encode-2ints) ( l h -- adr,len ) swap <# u#s drop ascii , hold u#s u#> ; | |
531 | ||
532 | : lookup-decode-unit ( unit$ -- pa.lo .. pa.hi ) | |
533 | ['] parse-2int ['] (decode-unit) " decode-unit" (lookup-method) | |
534 | ; | |
535 | ||
536 | : lookup-encode-unit ( pa.lo .. pa.hi -- unit$ ) | |
537 | ['] (encode-2ints) ['] (encode-unit) " encode-unit" (lookup-method) | |
538 | ; | |
539 | ||
540 | \ reset the current device cached encode/decode methods | |
541 | : reset-xxcoders ( -- ) | |
542 | ['] lookup-decode-unit is (decode-unit) | |
543 | ['] lookup-encode-unit is (encode-unit) | |
544 | ; | |
545 | ||
546 | : init-node ( #address-cells -- ) | |
547 | allocate-node-record | |
548 | ||
549 | '#adr-cells ! | |
550 | 'child !null-token \ No children yet | |
551 | 'peer !null-token \ Null peer | |
552 | ||
553 | #fixed-vals '#values ! \ Initialize data sizes | |
554 | #fixed-bufs '#buffers ! | |
555 | ||
556 | 'values !null-token \ No initial data values yet | |
557 | ||
558 | init-properties | |
559 | ||
560 | 0 support-node? ! \ Not a support node by default | |
561 | true inherit-node-flags? ! \ inherit by default | |
562 | reset-xxcoders | |
563 | ; | |
564 | ||
565 | : link-to-peer ( parent's-child-field -- ) | |
566 | dup token@ 'peer token! ( parent's-child-field ) | |
567 | current-device swap token! ( ) | |
568 | ; | |
569 | : device-node? ( voc -- flag ) | |
570 | voc-link begin another-link? while ( voc link ) | |
571 | 2dup voc> = if 2drop false exit then ( voc link ) | |
572 | >voc-link | |
573 | repeat ( voc ) | |
574 | drop true | |
575 | ; | |
576 | ||
577 | headers | |
578 | ||
579 | : new-node ( -- ) | |
580 | (vocabulary) current-device link, ( ) \ Up-link to parent device | |
581 | ||
582 | \ Save parent linkage address on stack for later use | |
583 | inherit-node-flags? @ ( in? ) | |
584 | support-node? @ over and ( in? support? ) | |
585 | 'child ( in? support? parent's-child-field ) | |
586 | #adr-cells init-node ( in? support? parent's-child-field ) | |
587 | link-to-peer ( in? support? ) | |
588 | support-node? ! ( in? ) | |
589 | inherit-node-flags? ! ( ) | |
590 | ; | |
591 | ||
592 | : new-device ( -- ) new-node extend-package ; | |
593 | ||
594 | : device-end ( -- ) | |
595 | \ The false will be patched later with device-context? | |
596 | false if reset-xxcoders then | |
597 | only forth also definitions package-level off | |
598 | ; | |
599 | ||
600 | : my-#adr-cells ( -- n ) | |
601 | my-self if \ Use current instance's package if there is a current instance | |
602 | my-voc also execute '#adr-cells @ previous | |
603 | else \ Otherwise use the active package | |
604 | '#adr-cells @ | |
605 | then | |
606 | ; | |
607 | ||
608 | \ my-address applies to the current instance, regardless of whether or | |
609 | \ not the active package corresponds to the current instance, thus it must | |
610 | \ use my-#adr-cells, which explicitly refers to the current instance's | |
611 | \ package. | |
612 | ||
613 | : my-address ( -- phys.lo .. ) | |
614 | addr my-adr0 my-#adr-cells 1- 1 max /n* bounds ?do i @ /n +loop | |
615 | ; | |
616 | : my-unit ( -- phys.lo .. ) | |
617 | addr my-unit-low my-#adr-cells /n* bounds ?do i @ /n +loop | |
618 | ; | |
619 | ||
620 | vocabulary root-node | |
621 | erase-voc-link null link, \ Root has no parent | |
622 | 0 init-node | |
623 | allot-package-data | |
624 | device-end | |
625 | ||
626 | : root-device ( -- ) only forth also ['] root-node push-device ; | |
627 | ||
628 | : finish-device ( -- ) reset-xxcoders finish-package-data pop-device ; | |
629 | ||
630 | \ The magic-device-types vocabulary contains words whose names are the | |
631 | \ same as the names of the device_type property values that we wish to | |
632 | \ recognize as special cases. "device_type" in the "magic-properties" | |
633 | \ vocabulary searches this vocabulary every time that a "device_type" | |
634 | \ property is created, and executes the corresponding word if a match | |
635 | \ is found. That word may look at the property name and value on the | |
636 | \ stack, but it must not remove them. However, it might wish to alter | |
637 | \ the value! | |
638 | ||
639 | vocabulary magic-device-types | |
640 | ||
641 | \ The magic-properties vocabulary contains words whose names are the | |
642 | \ same as the names of properties that we wish to recognize as special | |
643 | \ cases. "property" searches this vocabulary every time that an | |
644 | \ property is created, and executes the corresponding word if a match | |
645 | \ is found. That word may look at the property name and value on the | |
646 | \ stack, but it must not remove them. However, it might wish to alter | |
647 | \ either the name or the value! | |
648 | ||
649 | vocabulary magic-properties | |
650 | also magic-properties definitions | |
651 | : device_type ( value-str name-str -- value-str name-str ) | |
652 | 2over get-encoded-string ['] magic-device-types $vexecute | |
653 | ; | |
654 | previous definitions | |
655 | ||
656 | ||
657 | \ The parameter field of a property word contains: | |
658 | \ offset size | |
659 | \ Offset is the 32-bit positive distance from the beginning of the | |
660 | \ property-encoded byte array to the parameter field address. size is the | |
661 | \ 16-bit size of the property value array. This representation depends on | |
662 | \ the fact that property-encoded arrays are stored in the dictionary. | |
663 | ||
664 | headerless | |
665 | : make-property-name ( name-adr,len -- ) | |
666 | current token@ >r current-properties current token! | |
667 | ['] $header behavior >r | |
668 | ['] ($header) to $header | |
669 | $create | |
670 | r> to $header | |
671 | r> current token! | |
672 | ; | |
673 | ||
674 | headers | |
675 | 5 actions | |
676 | action: dup dup unaligned-l@ l->n - swap la1+ w@ ; | |
677 | action: ( adr,len apf -- ) | |
678 | tuck la1+ w! ( adr apf ) | |
679 | dup rot - swap unaligned-l! ( ) | |
680 | ; | |
681 | action: ; | |
682 | action: drop ; | |
683 | action: drop ; | |
684 | ||
685 | : (property) ( value-adr,len name-adr,len -- ) | |
686 | 2dup ['] magic-properties $vexecute ( value-str name-str ) | |
687 | 2dup current-properties (search-wordlist) if ( value-str name-str acf ) | |
688 | nip nip set ( ) | |
689 | else ( value-str name-str ) | |
690 | make-property-name ( value-str ) | |
691 | here rot - l, w, align use-actions ( ) | |
692 | then ( ) | |
693 | ; | |
694 | ||
695 | : property ( value-adr,len name-adr,len -- ) | |
696 | my-self if | |
697 | context token@ >r my-voc execute | |
698 | (property) | |
699 | r> context token! | |
700 | else | |
701 | (property) | |
702 | then | |
703 | ; | |
704 | ||
705 | : delete-property ( name-adr,len -- ) | |
706 | current-properties (search-wordlist) if | |
707 | >link current-properties remove-word | |
708 | then | |
709 | ; | |
710 | overload: forget \ name ( -- ) | |
711 | current token@ device-node? abort" Can't forget device methods" | |
712 | forget | |
713 | ; | |
714 | ||
715 | headerless | |
716 | : get-unit ( -- true | adr len false ) " reg" get-property ; | |
717 | ||
718 | : unit-str>phys- ( adr len -- phys.hi .. phys.lo ) | |
719 | '#adr-cells @ 0 ?do decode-int -rot loop 2drop ( phys.hi .. phys.lo ) | |
720 | ; | |
721 | ||
722 | : reorder ( xn .. x1 n -- x1 .. xn ) 0 ?do i roll loop ; | |
723 | ||
724 | : unit-str>phys ( adr len -- phys.lo .. phys.hi ) | |
725 | unit-str>phys- ( phys.hi .. phys.lo ) | |
726 | '#adr-cells @ reorder ( phys.lo .. phys.hi ) | |
727 | ; | |
728 | headers |