e8555c89 Andy McCall 1 month ago
1
namespace eval tas {
2
3
4
5
variable callback_list " "
6
variable callback_frame_id
7
variable callback_realtime_id
8
9
10
11
12
13
14
proc enable_periodic { callback } {
15
variable callback_list
16
variable callback_frame_id
17
variable callback_realtime_id
18
19
20
if { [ llength $ callback_list] = = 0 } {
21
set callback_frame_id [ after frame [ namespace code periodic_frame] ]
22
set callback_realtime_id [ after realtime 0.1 [ namespace code periodic_realtime] ]
23
}
24
25
26
lappend callback_list $ callback
27
28
29
$ callback
30
}
31
32
33
34
35
proc disable_periodic { callback } {
36
variable callback_list
37
variable callback_frame_id
38
variable callback_realtime_id
39
40
41
set idx [ lsearch -exact $ callback_list $ callback]
42
if { $ idx = = - 1 } return
43
set callback_list [ lreplace $ callback_list $ idx $ idx]
44
45
46
if { [ llength $ callback_list] = = 0 } {
47
after cancel $ callback_frame_id
48
after cancel $ callback_realtime_id
49
}
50
}
51
52
proc periodic_execute { } {
53
variable callback_list
54
foreach callback $ callback_list {
55
$ callback
56
}
57
}
58
proc periodic_frame { } {
59
variable callback_frame_id
60
variable callback_realtime_id
61
62
periodic_execute
63
64
65
after cancel $ callback_realtime_id
66
set callback_frame_id [ after frame [ namespace code periodic_frame] ]
67
set callback_realtime_id [ after realtime 0.1 [ namespace code periodic_realtime] ]
68
}
69
proc periodic_realtime { } {
70
variable callback_realtime_id
71
72
periodic_execute
73
74
75
set callback_realtime_id [ after realtime 0.1 [ namespace code periodic_realtime] ]
76
}
77
78
79
80
81
set_help_text toggle_frame_counter\
82
{ Toggles display of a frame counter in the lower right corner.}
83
84
proc toggle_frame_counter { } {
85
if { [ osd exists framecount] } {
86
disable_periodic framecount_update
87
osd destroy framecount
88
return " "
89
}
90
91
osd create rectangle framecount \
92
-x 269 -y 227 -h 7 -w 42 -scaled true \
93
-rgba " 0x0044aa80 0x2266dd80 0x0055cc80 0x44aaff80" \
94
-borderrgba 0x00000040 -bordersize 0.5
95
osd create text framecount.text -x 3 -y 1 -size 4 -rgba 0xffffffff
96
enable_periodic framecount_update
97
return " "
98
}
99
100
proc framecount_update { } {
101
102
103
104
105
set inside [ expr { ([ machine_info VDP_cycle_in_frame] < (6 * 25)) ? " " : " +" } ]
106
osd configure framecount.text -text " Frame: [ machine_info VDP_frame_count] $ inside"
107
}
108
109
110
111
112
proc get_start_of_frame_time { } {
113
expr { [ machine_info time] - [ machine_info VDP_cycle_in_frame] / (6.0 * 3579545)}
114
}
115
116
set_help_text prev_frame \
117
{ Rewind to the (start of) the previous frame. Useful
118
to bind to a key in combination with next_frame. You can also
119
go back N frames if you add N as the optional argument.}
120
proc prev_frame { { count 1 } } {
121
set t [ expr { [ get_start_of_frame_time ] - $ count * [ vdp::get_frame_duration ] } ]
122
if { $ t < 0 } { set t 0 }
123
reverse goto $ t
124
}
125
126
set_help_text next_frame \
127
{ Emulates until the (start of) the next frame, then pause emulation.
128
Useful to bind to a key and emulate frame by frame. You can also
129
go over the next N frames if you add N as the optional argument.}
130
proc next_frame { { count 1 } } {
131
set t [ expr { [ get_start_of_frame_time ] + $ count * [ vdp::get_frame_duration ] } ]
132
after time [ expr { $ t - [ machine_info time] } ] " set ::pause on"
133
set ::pause off
134
return " "
135
}
136
137
set_help_text start_of_frame \
138
{ Rewind to the start of the current frame.
139
See also prev_frame and next_frame.}
140
proc start_of_frame { } {
141
prev_frame 0
142
}
143
144
set_help_text advance_frame \
145
{ Emulate forward for the duration of one frame. The relative
146
timing position within the frame remains unchanged. You can also
147
advance N frames if you add N as the optional argument.}
148
proc advance_frame { { count 1 } } {
149
after time [ expr { $ count * [ vdp::get_frame_duration ] } ] " set ::pause on"
150
set ::pause off
151
return " "
152
}
153
154
set_help_text reverse_frame \
155
{ Emulate backward for the duration of one frame. The relative
156
timing position within the frame remains unchanged. You can also
157
reverse N frames if you add N as the optional argument.}
158
proc reverse_frame { { count 1 } } {
159
set t [ expr { [ machine_info time] - $ count * [ vdp::get_frame_duration ] } ]
160
if { $ t < 0 } { set t 0 }
161
reverse goto $ t
162
}
163
164
proc load_replay { name } {
165
reverse loadreplay -goto savetime $ name
166
return " "
167
}
168
169
170
171
172
user_setting create string current_replay_slot " Name of the current replay slot." slot0
173
174
proc list_slots { } {
175
set slots [ list ]
176
for { set i 0 } { $ i < = 9 } { incr i} {
177
lappend slots " slot$ i"
178
}
179
return $ slots
180
}
181
182
proc menu_create_slot_menu { } {
183
set items [ list_slots ]
184
set menu_def \
185
{ execute tas::set_slot
186
font-size 8
187
border-size 2
188
width 100
189
xpos 100
190
ypos 100
191
header { text "Select Replay Slot"
192
font-size 10
193
post-spacing 6 }}
194
195
return [ osd_menu::prepare_menu_list $ items 10 $ menu_def]
196
}
197
198
proc set_slot { item } {
199
osd_menu::menu_close_all
200
set ::current_replay_slot $ item
201
}
202
203
proc open_select_slot_menu { } {
204
osd_menu::do_menu_open [ menu_create_slot_menu ]
205
osd_menu::select_menu_item $ ::current_replay_slot
206
for { set i 0 } { $ i < [ llength [ tas::list_slots ] ] } { incr i} {
207
bind - layer slot_menu " $ i" " tas::set_slot [ lindex [ tas::list_slots ] $ i] ; tas::unbind_number_keys"
208
}
209
activate_input_layer slot_menu
210
}
211
212
proc unbind_number_keys { } {
213
deactivate_input_layer slot_menu
214
}
215
216
proc save_replay_slot { } {
217
reverse savereplay $ ::current_replay_slot
218
}
219
220
proc load_replay_slot { } {
221
load_replay $ ::current_replay_slot
222
}
223
224
225
226
227
variable keys
228
229
proc show_keys { } {
230
variable keys
231
232
233
set joy [ debug read joystickports 0 ]
234
235
foreach key $ keys {
236
show_key_press [ dict get $ key name] [ eval [ dict get $ key check_expr] ]
237
}
238
}
239
240
241
proc is_key_pressed { row bit } {
242
expr { ! ([ debug read keymatrix $ row] & (1 < < $ bit ))}
243
}
244
245
proc show_key_press { key state } {
246
set keycol [ expr { $ state ? 0xff000080 : " 0x0044aa80 0x2266dd80 0x0055cc80 0x44aaff80" } ]
247
osd configure cursors.$ key -rgba $ keycol
248
}
249
250
proc create_key { name x y } {
251
osd create rectangle cursors.$ name -x $ x -y $ y -w 16 -h 7 \
252
-rgba " 0x0044aa80 0x2266dd80 0x0055cc80 0x44aaff80" \
253
-bordersize 0.5 -borderrgba 0x00000040
254
osd create text cursors.$ name .text -x 2 -y 1 -text $ name -size 4 -rgba 0xffffffff
255
}
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
proc toggle_cursors { } {
277
variable keys
278
279
if { [ osd exists cursors] } {
280
disable_periodic show_keys
281
osd destroy cursors
282
} else {
283
osd create rectangle cursors -x 64 -y 219 -h 26 -w 204 -scaled true -rgba 0x00000000
284
if { [ info procs ::define_custom_keys] eq " ::define_custom_keys" } {
285
define_custom_keys
286
} else {
287
define_default_keys
288
}
289
foreach key $ keys {
290
create_key [ dict get $ key name] [ dict get $ key x] [ dict get $ key y]
291
}
292
enable_periodic show_keys
293
}
294
}
295
296
proc define_default_keys { } {
297
variable keys
298
299
set keys {{
300
name up
301
x 20
302
y 2
303
check_expr {expr {([is_key_pressed 8 5] || !($joy & 1))}}
304
} {
305
name down
306
x 20
307
y 14
308
check_expr {expr {([is_key_pressed 8 6] || !($joy & 2))}}
309
} {
310
name left
311
x 2
312
y 8
313
check_expr {expr {([is_key_pressed 8 4] || !($joy & 4))}}
314
} {
315
name right
316
x 38
317
y 8
318
check_expr {expr {([is_key_pressed 8 7] || !($joy & 8))}}
319
} {
320
name space
321
x 60
322
y 8
323
check_expr {expr {([is_key_pressed 8 0] || !($joy & 16))}}
324
} {
325
name m
326
x 78
327
y 8
328
check_expr {expr {([is_key_pressed 4 2] || !($joy & 32))}}
329
} {
330
name n
331
x 96
332
y 8
333
check_expr {is_key_pressed 4 3}
334
} {
335
name z
336
x 114
337
y 8
338
check_expr {is_key_pressed 5 7}
339
} {
340
name x
341
x 132
342
y 8
343
check_expr {is_key_pressed 5 5}
344
} {
345
name graph
346
x 150
347
y 8
348
check_expr {is_key_pressed 6 2}
349
} {
350
name ctrl
351
x 168
352
y 8
353
check_expr {is_key_pressed 6 1}
354
} {
355
name shift
356
x 186
357
y 8
358
check_expr {is_key_pressed 6 0}
359
}}
360
}
361
362
363
364
365
366
367
368
369
variable addr_watches [ dict create] ;
370
371
372
proc dict_insert_sorted { dictname key value } {
373
upvar $ dictname d
374
set i 0
375
dict for {k v} $ d {
376
if {$key <= $k} {
377
if {$key == $k} {
378
dict set d $key $value
379
return $d
380
}
381
break
382
}
383
incr i 2
384
}
385
set d [ linsert $ d $ i $ key $ value]
386
}
387
388
proc ram_watch_add { addr_str args } {
389
variable addr_watches
390
391
set type_dict [ dict create byte { peek 2 } b { peek 2 } \
392
u8 { peek 2 } s8 { peek_s8 2 } \
393
word { peek16 4 } w { peek16 4 } \
394
u16 { peek16 4 } s16 { peek_s16 4 } \
395
u16_LE { peek16 4 } s16_LE { peek_s16 4 } \
396
u16_BE { peek16_BE 4 } s16_BE { peek_s16_BE 4 } ]
397
set format_dict [ dict create dec " %d" hex " 0x%0SX" ]
398
399
400
set addr [ format 0x%04X $ addr_str]
401
if { ($ addr < 0) | | ($ addr > 0xffff) } {
402
error " Address must be in range 0x0..0xffff, got: $ addr_str"
403
}
404
405
set addr_already_watched [ dict exists $ addr_watches $ addr]
406
407
408
set desc " ?"
409
set type " byte"
410
set format " hex"
411
if { $ addr_already_watched} {
412
413
set desc [ dict get $ addr_watches $ addr -desc]
414
set type [ dict get $ addr_watches $ addr -type]
415
set format [ dict get $ addr_watches $ addr -format]
416
}
417
418
while { [ llength $ args] > 0 } {
419
set option [ lindex $ args 0 ]
420
switch - - $ option {
421
" -desc" {
422
set desc [ lindex $ args 1 ]
423
set args [ lrange $ args 2 end]
424
}
425
" -type" {
426
set type [ lindex $ args 1 ]
427
if { ! [ dict exists $ type_dict $ type] } {
428
error " Unsupported type: $ type . Choose from: [ dict keys $ type_dict] "
429
}
430
set args [ lrange $ args 2 end]
431
}
432
" -format" {
433
set format [ lindex $ args 1 ]
434
if { ! [ dict exists $ format_dict $ format] } {
435
error " Unsupported format: $ format . Choose from: [ dict keys $ format_dict] "
436
}
437
set args [ lrange $ args 2 end]
438
}
439
" default" {
440
error " Invalid option: $ option ."
441
}
442
}
443
}
444
445
lassign [ dict get $ type_dict $ type] peek_method num_hex_digits
446
set fmtStr1 [ dict get $ format_dict $ format]
447
set fmtStr2 [ string map [ list S $ num_hex_digits] $ fmtStr1]
448
set exprStr " set v \[ $ peek_method $ addr\] ; set r \" \[ expr {(\$ v < 0) ? \" -\" : \" \" }\] \[ format $ fmtStr2 \[ expr {abs(\$ v)}\] \] \" ; set r"
449
450
451
set old_nof_watches [ dict size $ addr_watches]
452
dict_insert_sorted addr_watches $ addr [ dict create -desc $ desc -format $ format -type $ type exprStr $ exprStr]
453
454
455
if { $ old_nof_watches = = 0 } {
456
ram_watch_init_widget
457
}
458
459
460
if { ! $ addr_already_watched} {
461
ram_watch_add_to_widget $ old_nof_watches
462
ram_watch_update_widget_size
463
}
464
465
ram_watch_update_addresses
466
if { $ old_nof_watches = = 0 } {
467
enable_periodic ram_watch_update_values
468
}
469
return " "
470
}
471
472
proc ram_watch_init_widget { } {
473
osd create rectangle ram_watch \
474
-x 0 -y 0 -h 240 -w 320 -scaled true -rgba 0x00000000
475
osd create rectangle ram_watch.addr \
476
-x 257 -y 1 -w 62 -h 221 \
477
-rgba " 0x0044aa80 0x2266dd80 0x0055cc80 0x44aaff80" \
478
-borderrgba 0x00000040 -bordersize 0.5
479
osd create text ram_watch.addr.title -text " RAM Watch" -x 2 -y 1 -size 4 -rgba 0xffffffff
480
}
481
482
proc ram_watch_update_widget_size { } {
483
variable addr_watches
484
set nr [ dict size $ addr_watches]
485
osd configure ram_watch.addr -h [ expr { 8 + ($ nr * 6)} ]
486
}
487
488
proc ram_watch_add_to_widget { nr } {
489
osd create rectangle ram_watch.addr.mem$ nr \
490
-x 2 -y [ expr { 8 + ($ nr * 6)} ] -h 5 -w 16 -rgba 0x40404080
491
osd create text ram_watch.addr.mem$ nr .text \
492
-size 4 -rgba 0xffffffff
493
osd create rectangle ram_watch.addr.val$ nr \
494
-x 19 -y [ expr { 8 + ($ nr * 6)} ] -h 5 -w 17 -rgba 0x40404080
495
osd create text ram_watch.addr.val$ nr .text \
496
-size 4 -rgba 0xffffffff
497
osd create rectangle ram_watch.addr.desc$ nr \
498
-x 37 -y [ expr { 8 + ($ nr * 6)} ] -h 5 -w 23 -rgba 0x40404080 -clip true
499
osd create text ram_watch.addr.desc$ nr .text \
500
-size 4 -rgba 0xffffffff
501
}
502
503
proc ram_watch_remove { addr_str } {
504
variable addr_watches
505
506
507
set addr [ format 0x%04X $ addr_str]
508
509
510
if { ! [ dict exists $ addr_watches $ addr] } {
511
512
return " "
513
}
514
515
516
dict unset addr_watches $ addr
517
518
set i [ dict size $ addr_watches]
519
520
521
osd destroy ram_watch.addr.mem$ i
522
osd destroy ram_watch.addr.val$ i
523
osd destroy ram_watch.addr.desc$ i
524
525
526
if { $ i = = 0 } {
527
disable_periodic ram_watch_update_values
528
osd destroy ram_watch
529
} else {
530
ram_watch_update_addresses
531
ram_watch_update_widget_size
532
}
533
return " "
534
}
535
536
proc ram_watch_clear { } {
537
variable addr_watches
538
set addr_watches [ dict create]
539
disable_periodic ram_watch_update_values
540
osd destroy ram_watch
541
return " "
542
}
543
544
proc ram_watch_update_addresses { } {
545
variable addr_watches
546
547
set i 0
548
dict for {addr v} $ addr_watches {
549
osd configure ram_watch.addr.mem$i.text -text $addr
550
osd configure ram_watch.addr.desc$i.text -text [dict get $v -desc]
551
incr i
552
}
553
}
554
555
proc ram_watch_update_values { } {
556
variable addr_watches
557
558
set i 0
559
dict for {addr v} $ addr_watches {
560
set exprStr [dict get $v exprStr]
561
osd configure ram_watch.addr.val$i.text -text [eval $exprStr]
562
incr i
563
}
564
}
565
566
proc ram_watch_save { name } {
567
variable addr_watches
568
569
570
set filtered_watches [ dict create]
571
dict for {addr v} $ addr_watches {
572
dict set filtered_watches $addr [dict filter $v key -*]
573
}
574
575
set directory [ file normalize $ ::env(OPENMSX_USER_DATA) /../ramwatches]
576
file mkdir $ directory
577
set fullname [ file join $ directory $ {name} .wch]
578
579
if { [ catch {
580
set the_file [ open $ fullname { WRONLY TRUNC CREAT} ]
581
puts $ the_file $ filtered_watches
582
close $ the_file
583
} errorText] } {
584
error " Failed to save to $ fullname : $ errorText"
585
}
586
return " Successfully saved RAM watch to $ fullname"
587
}
588
589
proc ram_watch_load { name } {
590
variable addr_watches
591
592
set directory [ file normalize $ ::env(OPENMSX_USER_DATA) /../ramwatches]
593
set fullname [ file join $ directory $ {name} .wch]
594
595
if { [ catch {
596
set the_file [ open $ fullname { RDONLY} ]
597
set new_addr_watches [ read $ the_file]
598
close $ the_file
599
} errorText] } {
600
error " Failed to load from $ fullname : $ errorText"
601
}
602
603
ram_watch_clear
604
dict for {addr v} $ new_addr_watches {
605
ram_watch_add $addr {*}$v
606
}
607
return " Successfully loaded $ fullname"
608
}
609
610
proc list_ram_watch_files { } {
611
set directory [ file normalize $ ::env(OPENMSX_USER_DATA) /../ramwatches]
612
set results [ list ]
613
foreach f [ lsort [ glob -tails -directory $ directory -type f -nocomplain *.wch] ] {
614
lappend results [ file rootname $ f]
615
}
616
return $ results
617
}
618
619
proc ram_watch { subcmd args } {
620
switch - - $ subcmd {
621
" add" { ram_watch_add {*}$ args}
622
" remove" { ram_watch_remove {*}$ args}
623
" clear" { ram_watch_clear {*}$ args}
624
" load" { ram_watch_load {*}$ args}
625
" save" { ram_watch_save {*}$ args}
626
default { error " Invalid subcommand: $ subcmd" }
627
}
628
}
629
630
set_help_proc ram_watch [ namespace code ram_watch_help]
631
proc ram_watch_help { args } {
632
switch - - [ lindex $ args 1 ] {
633
" add" { return {Add an address to the list of RAM watch addresses on the right side of the screen. The list will be updated in real time, whenever a value changes.
634
635
Syntax: ram_watch add <address> [<options>...]
636
Possible options are:
637
-desc <description> describes the address
638
-type <type> datatype: byte, word, u8, s8, u16, s16, u16_BE, ...
639
-format <format> formatting: dec, hex
640
}}
641
" remove" { return {Remove an address from the list of RAM watch addresses from the list of RAM watch addresses on the right side of the screen. When the last address is removed, the list will disappear automatically.
642
643
Syntax: ram_watch remove <address>
644
}}
645
" clear" { return {Removes all RAM watches.
646
647
Syntax: ram_watch clear
648
}}
649
" save" { return {Save the current list of RAM watches to a file.
650
651
Syntax: ram_watch save <filename>
652
}}
653
" load" { return {Load a list of RAM watches from file.
654
655
Syntax: ram_watch load <filename>
656
}}
657
default { return {Control the RAM watch functionality.
658
659
Syntax: ram_watch <sub-command> [<arguments>]
660
Where sub-command is one of:
661
add Add (or modify) a new RAM watch address
662
remove Remove a previously added address
663
clear Shortcut to remove all addresses
664
save Save current list of RAM watches to a file
665
load Load a previously saved list of RAM watches
666
667
Use 'help ram_watch <sub-command>' to get more detailed help on a specific sub-command.
668
}}
669
}
670
}
671
672
set_tabcompletion_proc ram_watch [ namespace code ram_watch_tabcompletion]
673
proc ram_watch_tabcompletion { args } {
674
if { [ llength $ args] = = 2 } {
675
return [ list " add" " remove" " clear" " save" " load" ]
676
}
677
switch - - [ lindex $ args 1 ] {
678
" add" { return [ list -desc -type -format] }
679
" load" -
680
" save" { return [ list_ram_watch_files ] }
681
default { return [ list ] }
682
}
683
}
684
685
686
687
variable lag_counter
688
variable lag_counter_wp
689
variable previous_frame_count 0
690
variable input_read_in_frame false
691
692
proc space_read { } {
693
variable input_read_in_frame
694
set input_read_in_frame true
695
}
696
697
proc toggle_lag_counter { } {
698
variable lag_counter
699
variable lag_counter_wp
700
701
if { [ osd exists lag_counter] } {
702
osd destroy lag_counter
703
debug remove_watchpoint $ lag_counter_wp
704
return " "
705
}
706
707
708
709
710
set lag_counter -1
711
712
set lag_counter_wp [ debug set_watchpoint read_io 0xa9 { [ expr [ debug read ioports 0xaa ] & 0x0f ] == 0x08 } { tas::space_read} ]
713
714
osd create rectangle lag_counter \
715
-x 269 -y 220 -h 7 -w 42 -scaled true \
716
-borderrgba 0x00000040 -bordersize 0.5
717
osd create text lag_counter.text -x 3 -y 1 -size 4 -rgba 0xffffffff
718
update_lag_counter ;
719
return " "
720
}
721
722
proc update_lag_counter { } {
723
update_lag_counter2
724
after frame [ namespace code update_lag_counter]
725
}
726
727
proc update_lag_counter2 { } {
728
variable lag_counter
729
variable previous_frame_count
730
variable input_read_in_frame
731
732
if { ! [ osd exists lag_counter] } return
733
734
set new_frame_count [ machine_info VDP_frame_count]
735
if { $ new_frame_count = = 1 } {
736
737
set lag_counter -1
738
}
739
740
741
742
if { $ previous_frame_count ! = $ new_frame_count | | $ lag_counter = = - 1 } {
743
set previous_frame_count $ new_frame_count
744
745
set col [ expr { ! $ input_read_in_frame ? 0xff000080 : " 0x0044aa80 0x2266dd80 0x0055cc80 0x44aaff80" } ]
746
osd configure lag_counter -rgba $ col
747
748
if { ! $ input_read_in_frame} {
749
incr lag_counter
750
osd configure lag_counter.text -text " Lag fr.: $ lag_counter"
751
} else {
752
set input_read_in_frame false
753
}
754
}
755
}
756
757
proc reset_lag_counter { } {
758
variable lag_counter
759
set lag_counter -1
760
update_lag_counter2
761
return " "
762
}
763
764
765
766
set_help_text toggle_movie_length_display\
767
{ Toggles display of the movie length in the upper right corner.}
768
769
proc toggle_movie_length_display { } {
770
if { [ osd exists movielength] } {
771
disable_periodic movielength_update
772
osd destroy movielength
773
return " "
774
}
775
776
osd create rectangle movielength \
777
-x 269 -y 234 -h 7 -w 42 -scaled true \
778
-rgba " 0x0044aa80 0x2266dd80 0x0055cc80 0x44aaff80" \
779
-borderrgba 0x00000040 -bordersize 0.5
780
osd create text movielength.text -x 3 -y 1 -size 4 -rgba 0xffffffff
781
enable_periodic movielength_update
782
return " "
783
}
784
785
proc movielength_update { } {
786
osd configure movielength.text -text " Length: [ utils::format_time_subseconds [ dict get [ reverse status] last_event] ] "
787
}
788
789
namespace export toggle_frame_counter
790
namespace export prev_frame
791
namespace export next_frame
792
namespace export start_of_frame
793
namespace export advance_frame
794
namespace export reverse_frame
795
namespace export toggle_cursors
796
namespace export ram_watch
797
namespace export toggle_lag_counter
798
namespace export reset_lag_counter
799
namespace export toggle_movie_length_display
800
}
801
802
namespace import tas::*