Commit | Line | Data |
---|---|---|
c906108c | 1 | # Simulator dejagnu utilities. |
9bea4d16 | 2 | # TODO: Switch to using dg-xxx helpers rather than parsing the files directly. |
c906108c SS |
3 | |
4 | # Communicate simulator path from sim_init to sim_version. | |
5 | # For some reason [board_info target sim] doesn't work in sim_version. | |
6 | # [Presumubly because the target has been "popped" by then. Odd though.] | |
7 | set sim_path "unknown-run" | |
8 | ||
9 | # Initialize the testrun. | |
10 | # Required by dejagnu. | |
11 | ||
12 | proc sim_init { args } { | |
13 | global sim_path | |
14 | set sim_path [board_info target sim] | |
15 | # Need to return an empty string (copied from GAS). | |
a9d96774 HPN |
16 | |
17 | # As gross as it is, we unset the linker script specified by the target | |
18 | # board. The simulator board file mips-sim.exp, sets ldscript to the | |
19 | # MIPS libgloss linker scripts which include libgcc (and possibly other | |
20 | # libraries), which the linker (used to link these tests rather than the | |
21 | # compiler) can't necessarily find. Similarly iq2000-sim.exp and | |
22 | # m68hc11-sim.exp. So, we make it a common rule to clear the slate for | |
23 | # all simulators. | |
24 | unset_currtarget_info ldscript | |
25 | ||
c906108c SS |
26 | return "" |
27 | } | |
28 | ||
29 | # Print the version of the simulator being tested. | |
30 | # Required by dejagnu. | |
31 | ||
32 | proc sim_version {} { | |
33 | global sim_path | |
34 | set version 0.5 | |
35 | clone_output "$sim_path $version\n" | |
36 | } | |
37 | ||
38 | # Cover function to target_compile. | |
39 | # Copied from gdb_compile. | |
40 | ||
41 | proc sim_compile { source dest type options } { | |
42 | set result [target_compile $source $dest $type $options] | |
43 | regsub "\[\r\n\]*$" "$result" "" result | |
44 | regsub "^\[\r\n\]*" "$result" "" result | |
45 | if { $result != "" } { | |
46 | clone_output "sim compile output: $result" | |
47 | } | |
48 | return $result | |
49 | } | |
50 | ||
51 | # Run a program on the simulator. | |
52 | # Required by dejagnu (at least ${tool}_run used to be). | |
53 | # | |
54 | # SIM_OPTS are options for the simulator. | |
55 | # PROG_OPTS are options passed to the simulated program. | |
56 | # At present REDIR must be "" or "> foo". | |
57 | # OPTIONS is a list of options internal to this routine. | |
58 | # This is modelled after target_compile. We want to be able to add new | |
59 | # options without having to update all our users. | |
60 | # Currently: | |
61 | # env(foo)=val - set environment variable foo to val for this run | |
62 | # timeout=val - set the timeout to val for this run | |
63 | # | |
64 | # The result is a list of two elements. | |
65 | # The first is one of pass/fail/etc. | |
66 | # The second is the program's output. | |
67 | # | |
68 | # This is different than the sim_load routine provided by | |
69 | # dejagnu/config/sim.exp. It's not clear how to pass arguments to the | |
70 | # simulator (not the simulated program, the simulator) with sim_load. | |
71 | ||
72 | proc sim_run { prog sim_opts prog_opts redir options } { | |
73 | global SIMFLAGS | |
74 | ||
75 | # Set the default value of the timeout. | |
76 | # FIXME: The timeout value we actually want is a function of | |
77 | # host, target, and testcase. | |
78 | set testcase_timeout [board_info target sim_time_limit] | |
79 | if { "$testcase_timeout" == "" } { | |
80 | set testcase_timeout [board_info host testcase_timeout] | |
81 | } | |
82 | if { "$testcase_timeout" == "" } { | |
83 | set testcase_timeout 240 ;# 240 same as in dejagnu/config/sim.exp. | |
84 | } | |
85 | ||
86 | # Initial the environment we pass to the testcase. | |
87 | set testcase_env "" | |
88 | ||
89 | # Process OPTIONS ... | |
90 | foreach o $options { | |
91 | if [regexp {^env\((.*)\)=(.*)} $o full var val] { | |
92 | set testcase_env "$testcase_env $var=$val" | |
93 | } elseif [regexp {^timeout=(.*)} $o full val] { | |
94 | set testcase_timeout $val | |
95 | } | |
96 | ||
97 | } | |
98 | ||
99 | verbose "testcase timeout is set to $testcase_timeout" 1 | |
100 | ||
101 | set sim [board_info target sim] | |
119da465 MF |
102 | if [string equal "" $sim] { |
103 | # Special case the simulator. These tests are designed to | |
104 | # be run inside of the simulator, not on the native host. | |
105 | # So if the sim target isn't set, default to the target run. | |
106 | # These global variables come from generated site.exp. | |
107 | global objdir | |
108 | global arch | |
109 | set sim "$objdir/../$arch/run" | |
110 | } | |
c906108c SS |
111 | |
112 | if [is_remote host] { | |
113 | set prog [remote_download host $prog] | |
114 | if { $prog == "" } { | |
115 | error "download failed" | |
bc81a370 | 116 | return -1 |
c906108c SS |
117 | } |
118 | } | |
119 | ||
120 | set board [target_info name] | |
121 | if [board_info $board exists sim,options] { | |
122 | set always_opts [board_info $board sim,options] | |
123 | } else { | |
124 | set always_opts "" | |
125 | } | |
126 | ||
127 | # FIXME: this works for UNIX only | |
128 | if { "$testcase_env" != "" } { | |
129 | set sim "env $testcase_env $sim" | |
130 | } | |
131 | ||
fcf640ec NC |
132 | if { [board_info target sim,protocol] == "sid" } { |
133 | set cmd "" | |
134 | set sim_opts "$sim_opts -e \"set cpu-loader file [list ${prog}]\"" | |
135 | } else { | |
136 | set cmd "$prog" | |
137 | } | |
138 | ||
139 | send_log "$sim $always_opts $SIMFLAGS $sim_opts $cmd $prog_opts\n" | |
c906108c SS |
140 | |
141 | if { "$redir" == "" } { | |
fcf640ec | 142 | remote_spawn host "$sim $always_opts $SIMFLAGS $sim_opts $cmd $prog_opts" |
c906108c | 143 | } else { |
fcf640ec | 144 | remote_spawn host "$sim $always_opts $SIMFLAGS $sim_opts $cmd $prog_opts $redir" writeonly |
c906108c SS |
145 | } |
146 | set result [remote_wait host $testcase_timeout] | |
147 | ||
148 | set return_code [lindex $result 0] | |
149 | set output [lindex $result 1] | |
150 | # Remove the \r part of "\r\n" so we don't break all the patterns | |
151 | # we want to match. | |
152 | regsub -all -- "\r" $output "" output | |
153 | ||
154 | if [is_remote host] { | |
155 | # clean up after ourselves. | |
156 | remote_file host delete $prog | |
157 | } | |
158 | ||
159 | # ??? Not sure the test for pass/fail is right. | |
160 | # We just care that the simulator ran correctly, not whether the simulated | |
161 | # program return 0 or non-zero from `main'. | |
162 | set status fail | |
163 | if { $return_code == 0 } { | |
164 | set status pass | |
165 | } | |
166 | ||
167 | return [list $status $output] | |
168 | } | |
169 | ||
170 | # Run testcase NAME. | |
171 | # NAME is either a fully specified file name, or just the file name in which | |
172 | # case $srcdir/$subdir will be prepended. | |
104c1213 JM |
173 | # REQUESTED_MACHS is a list of machines to run the testcase on. If NAME isn't |
174 | # for the specified machine(s), it is ignored. | |
175 | # Typically REQUESTED_MACHS contains just one element, it is up to the caller | |
176 | # to iterate over the desired machine variants. | |
177 | # | |
178 | # The file can contain options in the form "# option(mach list): value". | |
c906108c SS |
179 | # Possibilities: |
180 | # mach: [all | machine names] | |
181 | # as[(mach-list)]: <assembler options> | |
182 | # ld[(mach-list)]: <linker options> | |
0641104b | 183 | # cc[(mach-list)]: <compiler options> |
c906108c | 184 | # sim[(mach-list)]: <simulator options> |
fa0cbd5a | 185 | # progopts: <arguments to the program being simulated> |
0ab7df8a DB |
186 | # output: program output pattern to match with string-match |
187 | # xerror: program is expected to return with a "failure" exit code | |
27509da0 HPN |
188 | # xfail: <PRMS-opt> <target-triplets-where-test-fails> |
189 | # kfail: <PRMS> <target-triplets-where-test-fails> | |
c906108c SS |
190 | # If `output' is not specified, the program must output "pass" if !xerror or |
191 | # "fail" if xerror. | |
192 | # The parens in "optname()" are optional if the specification is for all machs. | |
310ca70c HPN |
193 | # Multiple "output", "xfail" and "kfail" options concatenate. |
194 | # The xfail and kfail arguments are space-separated target triplets and PRIDs. | |
195 | # There must be a PRMS (bug report ID) specified for kfail, while it's | |
196 | # optional for xfail. | |
c906108c | 197 | |
104c1213 | 198 | proc run_sim_test { name requested_machs } { |
c906108c | 199 | global subdir srcdir |
104c1213 | 200 | global SIMFLAGS |
c906108c | 201 | global opts |
0ab7df8a | 202 | global cpu_option |
a3ef5243 DD |
203 | global global_as_options |
204 | global global_ld_options | |
0641104b | 205 | global global_cc_options |
a3ef5243 | 206 | global global_sim_options |
c906108c SS |
207 | |
208 | if [string match "*/*" $name] { | |
209 | set file $name | |
210 | set name [file tail $name] | |
211 | } else { | |
212 | set file "$srcdir/$subdir/$name" | |
213 | } | |
214 | ||
215 | set opt_array [slurp_options "${file}"] | |
216 | if { $opt_array == -1 } { | |
217 | unresolved $subdir/$name | |
218 | return | |
219 | } | |
0ab7df8a DB |
220 | # Clear default options |
221 | set opts(as) "" | |
222 | set opts(ld) "" | |
0641104b | 223 | set opts(cc) "" |
fa0cbd5a | 224 | set opts(progopts) "" |
0ab7df8a DB |
225 | set opts(sim) "" |
226 | set opts(output) "" | |
227 | set opts(mach) "" | |
228 | set opts(timeout) "" | |
c906108c | 229 | set opts(xerror) "no" |
310ca70c HPN |
230 | set opts(xfail) "" |
231 | set opts(kfail) "" | |
744b9a19 | 232 | set seen_output 0 |
c906108c | 233 | |
a3ef5243 DD |
234 | if ![info exists global_as_options] { |
235 | set global_as_options "" | |
236 | } | |
237 | if ![info exists global_ld_options] { | |
238 | set global_ld_options "" | |
239 | } | |
0641104b MF |
240 | if ![info exists global_cc_options] { |
241 | set global_cc_options "" | |
242 | } | |
a3ef5243 DD |
243 | if ![info exists global_sim_options] { |
244 | set global_sim_options "" | |
245 | } | |
246 | ||
0ab7df8a DB |
247 | # Clear any machine specific options specified in a previous test case |
248 | foreach m $requested_machs { | |
249 | if [info exists opts(as,$m)] { | |
250 | unset opts(as,$m) | |
251 | } | |
252 | if [info exists opts(ld,$m)] { | |
253 | unset opts(ld,$m) | |
254 | } | |
0641104b MF |
255 | if [info exists opts(cc,$m)] { |
256 | unset opts(cc,$m) | |
257 | } | |
0ab7df8a DB |
258 | if [info exists opts(sim,$m)] { |
259 | unset opts(sim,$m) | |
260 | } | |
261 | } | |
262 | ||
c906108c SS |
263 | foreach i $opt_array { |
264 | set opt_name [lindex $i 0] | |
265 | set opt_machs [lindex $i 1] | |
266 | set opt_val [lindex $i 2] | |
267 | if ![info exists opts($opt_name)] { | |
268 | perror "unknown option $opt_name in file $file" | |
269 | unresolved $subdir/$name | |
270 | return | |
271 | } | |
5eba45c1 HPN |
272 | # Multiple "output" specifications concatenate, they don't override. |
273 | if { $opt_name == "output" } { | |
274 | set opt_val "$opts(output)$opt_val" | |
744b9a19 | 275 | set seen_output 1 |
5eba45c1 | 276 | } |
310ca70c HPN |
277 | # Similar with "xfail" and "kfail", but arguments are space-separated. |
278 | if { $opt_name == "xfail" || $opt_name == "kfail" } { | |
279 | set opt_val "$opts($opt_name) $opt_val" | |
280 | } | |
281 | ||
c906108c SS |
282 | foreach m $opt_machs { |
283 | set opts($opt_name,$m) $opt_val | |
284 | } | |
285 | if { "$opt_machs" == "" } { | |
286 | set opts($opt_name) $opt_val | |
287 | } | |
288 | } | |
289 | ||
290 | set testname $name | |
291 | set sourcefile $file | |
744b9a19 | 292 | if { $seen_output == 0 } { |
c906108c SS |
293 | if { "$opts(xerror)" == "no" } { |
294 | set opts(output) "pass\n" | |
295 | } else { | |
296 | set opts(output) "fail\n" | |
297 | } | |
298 | } | |
299 | # Change \n sequences to newline chars. | |
300 | regsub -all "\\\\n" $opts(output) "\n" opts(output) | |
301 | ||
104c1213 JM |
302 | set testcase_machs $opts(mach) |
303 | if { "$testcase_machs" == "all" } { | |
304 | set testcase_machs $requested_machs | |
305 | } | |
306 | ||
307 | foreach mach $testcase_machs { | |
308 | if { [lsearch $requested_machs $mach] < 0 } { | |
309 | verbose -log "Skipping $mach version of $name, not requested." | |
310 | continue | |
311 | } | |
312 | ||
313 | verbose -log "Testing $name on machine $mach." | |
c906108c | 314 | |
310ca70c HPN |
315 | # Time to setup xfailures and kfailures. |
316 | if { "$opts(xfail)" != "" } { | |
317 | verbose -log "xfail: $opts(xfail)" | |
318 | # Using eval to make $opts(xfail) appear as individual | |
319 | # arguments. | |
320 | eval setup_xfail $opts(xfail) | |
321 | } | |
322 | if { "$opts(kfail)" != "" } { | |
323 | verbose -log "kfail: $opts(kfail)" | |
324 | eval setup_kfail $opts(kfail) | |
325 | } | |
326 | ||
c906108c SS |
327 | if ![info exists opts(as,$mach)] { |
328 | set opts(as,$mach) $opts(as) | |
329 | } | |
104c1213 | 330 | |
0ab7df8a DB |
331 | set as_options "$opts(as,$mach) -I$srcdir/$subdir" |
332 | if [info exists cpu_option] { | |
333 | set as_options "$as_options $cpu_option=$mach" | |
334 | } | |
0641104b | 335 | regsub {(^ *| +)([^ ]+)} "$as_options $global_as_options" { -Wa,\2} c_as_options |
c906108c SS |
336 | |
337 | if ![info exists opts(ld,$mach)] { | |
338 | set opts(ld,$mach) $opts(ld) | |
339 | } | |
0641104b MF |
340 | regsub {(^ *| +)([^ ]+)} "$opts(ld,$mach) $global_ld_options" { -Wl,\2} c_ld_options |
341 | ||
342 | if ![info exists opts(cc,$mach)] { | |
343 | set opts(cc,$mach) $opts(cc) | |
344 | } | |
104c1213 | 345 | |
0641104b MF |
346 | if [string match "*.c" $sourcefile] { |
347 | set comp_output [target_compile $sourcefile ${name}.x "executable" \ | |
348 | [list "incdir=$srcdir/$subdir" "additional_flags=$c_as_options $c_ld_options $opts(cc,$mach) $global_cc_options"]] | |
349 | set method "compiling/linking" | |
350 | } else { | |
351 | if [string match "*.S" $sourcefile] { | |
352 | set comp_output [target_compile $sourcefile ${name}.o "object" \ | |
353 | [list "incdir=$srcdir/$subdir" "additional_flags=$c_as_options"]] | |
354 | set method "compiling" | |
355 | } else { | |
356 | set comp_output [target_assemble $sourcefile ${name}.o "$as_options $global_as_options"] | |
357 | set method "assembling" | |
358 | } | |
359 | ||
360 | if ![string match "" $comp_output] { | |
361 | verbose -log "$comp_output" 3 | |
362 | fail "$mach $testname (${method})" | |
363 | continue | |
364 | } | |
365 | ||
366 | set comp_output [target_link ${name}.o ${name}.x "$opts(ld,$mach) $global_ld_options"] | |
367 | set method "linking" | |
368 | } | |
c906108c SS |
369 | |
370 | if ![string match "" $comp_output] { | |
371 | verbose -log "$comp_output" 3 | |
0641104b | 372 | fail "$mach $testname (${method})" |
c906108c SS |
373 | continue |
374 | } | |
375 | ||
376 | # If no machine specific options, default to the general version. | |
377 | if ![info exists opts(sim,$mach)] { | |
378 | set opts(sim,$mach) $opts(sim) | |
379 | } | |
380 | ||
381 | # Build the options argument. | |
382 | set options "" | |
383 | if { "$opts(timeout)" != "" } { | |
384 | set options "$options timeout=$opts(timeout)" | |
385 | } | |
386 | ||
fa0cbd5a | 387 | set result [sim_run ${name}.x "$opts(sim,$mach) $global_sim_options" "$opts(progopts)" "" "$options"] |
c906108c SS |
388 | set status [lindex $result 0] |
389 | set output [lindex $result 1] | |
390 | ||
391 | if { "$status" == "pass" } { | |
392 | if { "$opts(xerror)" == "no" } { | |
393 | if [string match $opts(output) $output] { | |
394 | pass "$mach $testname" | |
2345c93c | 395 | file delete ${name}.o ${name}.x |
c906108c SS |
396 | } else { |
397 | verbose -log "output: $output" 3 | |
398 | verbose -log "pattern: $opts(output)" 3 | |
f18ee7ef | 399 | fail "$mach $testname (execution)" |
c906108c SS |
400 | } |
401 | } else { | |
402 | verbose -log "`pass' return code when expecting failure" 3 | |
f18ee7ef | 403 | fail "$mach $testname (execution)" |
c906108c SS |
404 | } |
405 | } elseif { "$status" == "fail" } { | |
406 | if { "$opts(xerror)" == "no" } { | |
f18ee7ef | 407 | fail "$mach $testname (execution)" |
c906108c SS |
408 | } else { |
409 | if [string match $opts(output) $output] { | |
410 | pass "$mach $testname" | |
2345c93c | 411 | file delete ${name}.o ${name}.x |
c906108c SS |
412 | } else { |
413 | verbose -log "output: $output" 3 | |
414 | verbose -log "pattern: $opts(output)" 3 | |
f18ee7ef | 415 | fail "$mach $testname (execution)" |
c906108c SS |
416 | } |
417 | } | |
418 | } else { | |
419 | $status "$mach $testname" | |
420 | } | |
421 | } | |
422 | } | |
423 | ||
424 | # Subroutine of run_sim_test to process options in FILE. | |
425 | ||
426 | proc slurp_options { file } { | |
9bea4d16 | 427 | global subdir srcdir |
c906108c SS |
428 | if [catch { set f [open $file r] } x] { |
429 | #perror "couldn't open `$file': $x" | |
430 | perror "$x" | |
431 | return -1 | |
432 | } | |
433 | set opt_array {} | |
434 | # whitespace expression | |
435 | set ws {[ ]*} | |
436 | set nws {[^ ]*} | |
437 | # whitespace is ignored anywhere except within the options list; | |
438 | # option names are alphabetic only | |
439 | set pat "^#${ws}(\[a-zA-Z\]*)\\(?(\[^):\]*)\\)?$ws:${ws}(.*)$ws\$" | |
fbd93201 DB |
440 | # Allow arbitrary lines until the first option is seen. |
441 | set seen_opt 0 | |
c906108c SS |
442 | while { [gets $f line] != -1 } { |
443 | set line [string trim $line] | |
444 | # Whitespace here is space-tab. | |
445 | if [regexp $pat $line xxx opt_name opt_machs opt_val] { | |
446 | # match! | |
9bea4d16 MF |
447 | set opt_val [string map [list \ |
448 | {$srcdir} "$srcdir" \ | |
449 | {$subdir} "$subdir" \ | |
450 | ] "$opt_val"] | |
c906108c | 451 | lappend opt_array [list $opt_name $opt_machs $opt_val] |
fbd93201 | 452 | set seen_opt 1 |
c906108c | 453 | } else { |
fbd93201 | 454 | if { $seen_opt } { |
c906108c SS |
455 | break |
456 | } | |
457 | } | |
c906108c SS |
458 | } |
459 | close $f | |
460 | return $opt_array | |
461 | } |