##// END OF EJS Templates
Bug 1084...
paul -
r369:3813be439915 R3++ draft
parent child
Show More
This diff has been collapsed as it changes many lines, (681 lines changed) Show them Hide them
@@ -0,0 +1,681
1 #! /usr/bin/tclsh
2 #
3 # TCL script to scan disassembled programs against the "LEON3FT Stale Cache
4 # Entry After Store with Data Tag Parity Error" errata, GRLIB-TN-0009.
5 #
6 # The following Cobham components are affected by GRLIB-TN-0009:
7 # - GR712RC
8 # - LEON3FT-RTAX (all versions)
9 # - UT699
10 # - UT699E
11 # - UT700
12 #
13 # For information on how custom LEON3 systems may be affected, see
14 # GRLIB-TN-0009.
15 #
16 # Copyright (C) 2016, Cobham Gaisler
17 #
18 # Usage: sparc-elf-objdump -d program | leon3ft-b2bst-scan.tcl
19 #
20 # Command line parameters:
21 # -nonote: Do not print NOTE messages.
22 # -noinfo: Do not print INFO messages.
23 # -silent: Do not print NOTE or INFO messages.
24 #
25 # Return values:
26 # 0: No potential error locations found.
27 # 1: At least one potential error location found.
28 #
29 # Rev. history:
30 # rev 1, MH, Initial revision, based on ut699scan.tcl. Add scanning for
31 # store-store errata, reorganize comments
32 # rev 2, MA, Restruction and clean-up, fixed Sequence B.
33 # rev 3, MA, Added decoding of casa instruction, exit status and verbosity
34 # parameters.
35 # rev 4, MA, Reduced false warnings due to Store into Alternate space
36 # instructions which can not trig the errata. Script renamed to
37 # leon3ft-b2bst-scan.tcl.
38 #
39 # Note 1: Two modes are available with respect to call/ret (dslot_mode):
40 # 1) ret, and call are assumed not to have stores in their delay slots.
41 # The tool will warn if any such operations are found in the delay
42 # slot of ret,call during the scan
43 # 0) ret and call may have stores in their delay slots
44 # The tool will not warn if any such operations are found in the
45 # delay slot during the scan. Instead it will assume this
46 # possibility exists when evaluating insns following a function call
47 #
48
49 ### CONFIGURATION
50 set b2bst_seqa_scan 1; # enable/disable scanning for Sequence A
51 set b2bst_seqb_scan 1; # enable/disable scanning for Sequence B
52 # set dslot_mode 0; # assume store can be in delay slot of call,jmpl
53 set dslot_mode 1; # do not allow store in delay slot of call,jmpl
54 ###
55
56 # Mask values for types of output messages
57 set MSG_INFO 1; # Information on things to check manually.
58 set MSG_NOTE 2; # Notices on branch following
59 set msglevel [expr {$MSG_INFO | $MSG_NOTE}]
60
61 set errata_desc "LEON3FT Stale Cache Entry After Store with Data Tag Parity Error"
62 set util_rev 4
63 set util_date "20170215"
64
65 set b2bst_seqa_desc "Sequence A"
66 set b2bst_seqb_desc "Sequence B"
67
68 set op_count 0
69 set lineskip_count 0
70 set line_count 0
71 set err_count 0
72 set fn_count 0
73 set fninst_count 0
74
75 proc puts_info {str} {
76 global msglevel MSG_INFO
77 if {$msglevel & $MSG_INFO} { puts "INFO: $str" }
78 }
79
80 proc puts_note {str} {
81 global msglevel MSG_NOTE
82 if {$msglevel & $MSG_NOTE} { puts "NOTE: $str" }
83 }
84
85 # ----------------------------------------------------------------------------
86 # Routine that decodes specified opcode and returns list of
87 # 0 :optype Class of opcode
88 # one of call,jmpl,branch,sethi,ld,st,atomic,alu,fpop,save,restore
89 # 1 :target-reg Register modified by op
90 # 2 :source-reg1 First source register (rs1)
91 # 3 :source-reg2 Second source register (rs2)
92 # 4 :store-reg Source register for store data
93 # regs are numbered 0-31 integer regs, 32-63 FP regs
94 # 5 :double-flag
95 # ORed mask: 8) target-reg is DP, 4) sreg1 is DP, 2) sreg2 is DP, 1) store-reg is DP
96 # 6 :immed Immediate operand
97 # 7 :nnpc1 Next instructions nPC if branch not taken (normal case), normally nPC+4
98 # 8 :nnpc2 Next instruction's nPC if branch is taken, if not branch then nnpc2=nnpc1
99 # 9 :annul
100 # ORed mask: next inst annulled if 2) branch not taken 1) branch taken
101 # 10:bubbles Number of extra cycles spent in decode stage (bubbles inserted)
102 proc decode_inst { opcode {pc "0x00000000"} {npc "0x00000004"}} {
103 # Some "sta" instructions do not trig the errata. The related ASI:s are
104 # defined here.
105 set safeasi [list 0x02 0x03 0x04 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x13 0x14 0x15 0x18 0x19 0x1c 0x1d 0x1e]
106 #Default values if no cond matches
107 set opname "unknown"
108 set destreg 0
109 set sreg1 0
110 set sreg2 0
111 set streg 0
112 set dblflag 0
113 set immed 0
114
115 if { [string is integer $npc] } {
116 set nnpc1 [format "0x%08x" [ expr {$npc+4} ] ]
117 } else {
118 set nnpc1 "$npc+4"
119 }
120 set nnpc2 $nnpc1
121 set annul 0
122 set bubbles 0
123 #Decode
124 set op1 [ expr {$opcode >> 30} ]
125 if { $op1 == 1 } {
126 set opname "call"
127 set disp [ expr { ($opcode & 0x3fffffff)<<2 } ]
128 set nnpc1 [ format "0x%08x" [ expr { $pc + $disp } ] ]
129 set nnpc2 $nnpc1
130 } elseif { $op1 == 0 } {
131 set op2 [ expr {($opcode >> 22) & 7} ]
132 # NOTE: 2=Bicc, 6=FBcc, 7=CBcc
133 if { $op2 == 2 || $op2 == 6 } {
134 set opname "branch"
135 set disp [expr { ($opcode & 0x3fffff) << 2 } ]
136 if { $disp > 0x800000 } { set disp [expr {$disp - 0x1000000}] }
137 # Todo check cond,annul, handle always or never
138 set nnpc2 [ format "0x%08x" [ expr { $pc + $disp } ] ]
139 set cond [ expr { ($opcode >> 25) & 15 } ]
140 set annulbit [ expr { $opcode & 0x20000000 } ]
141 if { $cond == 0 } { # Branch never
142 set nnpc2 $nnpc1
143 if { $annulbit } { set annul 3 }
144 } elseif { $cond == 8 } { # Branch always
145 set nnpc1 $nnpc2
146 if { $annulbit } { set annul 3 }
147 } else { # True cond branch
148 if { $annulbit } { set annul 2 }
149 }
150 } elseif { $op2 == 4 } {
151 set opname "sethi"
152 set destreg [ expr { ($opcode >> 25) & 31 } ]
153 set immed [ expr { ($opcode & 0x3fffff) << 10 } ]
154 }
155 } elseif { $op1 == 3 } {
156 # SPARC V8 Table F-4
157 # set opname "mem" - changed to use ld/st/atomic instead
158 set op3 [ expr { ($opcode >> 19) & 63 } ]
159 set rs1 [ expr { (($opcode >> 14) & 31) } ]
160 set rs2 [ expr { (($opcode ) & 31) } ]
161 set rd [ expr { (($opcode >> 25) & 31) } ]
162 set sreg1 $rs1
163 if { $opcode & 0x2000 } {
164 set immed [ expr { $opcode & 0x1fff } ]
165 if { $immed > 0xfff } { set immed [ expr { $immed-(0x2000) } ] }
166 } else {
167 set sreg2 $rs2
168 }
169 if { (($op3 & 13) == 13) || ($op3 == 0x3c) } {
170 # Atomic ldst/swap/casa
171 set opname "atomic"
172 set destreg $rd
173 set streg $rd
174 } else {
175 # Adjust reg no if FP ld/st (op3[5]=1)
176 if { ($op3 & 0x20) != 0 } { set rd [expr {32 + $rd} ] }
177 # Check if read or write op3[2]
178 if { ($op3 & 4) != 0 } {
179 set opname "st"
180 set streg $rd
181 set allow_safe_sta true
182 if { $allow_safe_sta && (($op3 & 0x3c) == 0x14) } {
183 # op3 is 0x14, 0x15, 0x16 or 0x17 (sta, stba, stha or stda)
184 # (if i = 0)
185 set asi [expr { (($opcode >> 5) & 0xff) }]
186 set safematch [lsearch -exact -integer $safeasi $asi]
187 if {0 <= $safematch} {
188 set opname "sta_safe"
189 }
190 }
191 } else {
192 set opname "ld"
193 set destreg $rd
194 }
195 # Check size op3[1:0]
196 if { ($op3 & 3) == 3 } {
197 if { $opname eq "st" } { set dblflag 1 } else { set dblflag 8 }
198 }
199 }
200 } else {
201 set op3 [ expr { ($opcode >> 19) & 63 } ]
202 if { $op3 == 0x34 || $op3 == 0x35 } {
203 set opname "fpop"
204 set opf [ expr { ($opcode >> 5) & 0x1ff } ]
205 set rs1 [ expr { 32 + (($opcode >> 14) & 31) } ]
206 set rs2 [ expr { 32 + (($opcode ) & 31) } ]
207 set rd [ expr { 32 + (($opcode >> 25) & 31) } ]
208 # opf[1:0] corresponds to operand size of rs2
209 # opf[7:6]=11 is conv op, opf[3:2] gives opsize of rd, rs1 unused
210 # opf[7:6]=00 is single-operand op, rd same size as rs2, rs1 unused
211 # opf[7:4]=0100 regular op, rs1,rd same size as rs2
212 # opf[7:4]=0101 comp op, rd unused, rs1 same size as rs2
213 # opf[7:4]=0110 conv+mul, opf[3:2] gives opsize of rd, rs1 same size as rs2
214 set sreg2 $rs2
215 if { ($opf & 3) > 1 } { set dblflag 2 }
216 if { ($opf & 0xc0) == 0x40 } {
217 set sreg1 $rs1
218 if { $dblflag & 2 } { set dblflag [ expr { $dblflag | 4 } ] }
219 }
220 if { ($opf & 0xc0) == 0xc0 || ($opf & 0xf0) == 0x60 } {
221 set destreg $rd
222 if { ($opf & 0xc) > 4 } { set dblflag [ expr { $dblflag | 8 } ] }
223 } elseif { ($opf & 0xf0) != 0x50 } {
224 set destreg $rd
225 if { $dblflag & 2 } { set dblflag [ expr { $dblflag | 8 } ] }
226 }
227 } else {
228 set opname "alu"
229 set destreg [ expr { (($opcode >> 25) & 31) } ]
230 set sreg1 [ expr { (($opcode >> 14) & 31) } ]
231 if { $opcode & 0x2000 } {
232 set immed [ expr { $opcode & 0x1fff } ]
233 if { $immed > 0xfff } { set immed [ expr { $immed-(0x2000) } ] }
234 } else {
235 set sreg2 [ expr { (($opcode ) & 31) } ]
236 }
237 if { $op3 == 0x38 } {
238 set opname "jmpl"
239 set nnpc1 "jmpaddr"
240 set nnpc2 "jmpaddr"
241 set bubbles 2
242 } elseif { $op3 == 0x3c } {
243 set opname "save"
244 } elseif { $op3 == 0x3d } {
245 set opname "restore"
246 }
247 }
248 }
249 #Return values
250 return [list $opname $destreg $sreg1 $sreg2 $streg $dblflag $immed $nnpc1 $nnpc2 $annul $bubbles]
251 }
252
253 proc is_store { opcode } {
254 set op1 [ expr { ($opcode >> 30) } ]
255 set op3 [ expr { ($opcode >> 19) & 63 } ]
256 return [expr {($op1 == 3) && (($op3 & 0xc) == 0x4)}]
257 }
258
259 # -------------------------------------------------------------------------------------
260
261 proc unpack { l args } {
262 for { set i 0 } { $i < [llength $args] } { incr i } {
263 uplevel 1 "set [lindex $args $i] [lindex $l $i]"
264 }
265 }
266
267 # --------- Postprocessing on whole function
268
269 # Number of instructions printed is starti + 2
270 proc print_trace { fnpc state fnarr seqstart {starti 4}} {
271 upvar $fnarr fnops
272
273 puts " # PC Opcode"
274 set cnt [expr {$seqstart-$starti}]
275 for { set x $starti } { $x > -2 } { set x [expr {$x-1}] } {
276 incr cnt
277 if { $cnt > 0 } { set cntv $cnt } else { set cntv " " }
278 if { $x >= 0 } { set pc [lindex $state $x] } else { set pc $fnpc }
279 if { $pc eq "?" || $pc eq "call" || $pc eq "ret" || $pc eq "dslot" } {
280 puts " $cntv (other fn) $pc"
281 } else {
282 if { [string index $pc 0] eq "A" } {
283 set pc [string range $pc 1 end]
284 set annul " (annulled)"
285 } else {
286 set annul ""
287 }
288 if { [info exists fnops($pc)] } {
289 set op $fnops($pc)
290 } else {
291 set op [list "0x???????? (outside func)"]
292 }
293 puts " $cntv $pc [join $op] $annul"
294 }
295 }
296 puts ""
297 }
298
299 # Routine called by scan_wholefunc_main to check
300 # instruction sequences described in GRLIB-TN-009, Issue 1.0
301 #
302 # "Sequence A"
303 # 1. store of word size or less (st / stb / sth / stf)
304 # 2. any single instruction that is not a load or store
305 # 3. any store instruction (st / stb / sth / stf / std / stdf)
306 #
307 # "Sequence B"
308 # 1. store of double word size (std / stdf)
309 # 2. any store instruction (st / stb / sth / stf / std / stdf)
310 proc scan_b2bst { fnname fnpc fnop opdec fnarr state } {
311 global b2bst_seqa_scan
312 global b2bst_seqb_scan
313 upvar $fnarr fnops
314 global dslot_mode
315
316 # Check latest 3 insn if they can be st/std/regular
317 set pca [list $fnpc [lindex $state 0] [lindex $state 1]]
318 set can_be_arr [list]
319 for { set i 0 } { $i < 3 } { incr i } {
320 set can_be [list 0 0 0] ; # st std regular
321 set pcv [lindex $pca $i]
322 if { $pcv eq "?" } {
323 set can_be [list 1 1 1]
324 } elseif { $pcv eq "dslot" } {
325 set can_be [list [expr {1-$dslot_mode}] [expr {1-$dslot_mode}] 1]
326 } elseif { [string index $pcv 0] eq "A" || $pcv eq "call" || $pcv eq "ret" } {
327 set can_be [list 0 0 1]
328 } else {
329 set op $fnops($pcv)
330 set ophex [lindex $op 0]
331 set opdec [decode_inst $ophex]
332 set optype [lindex $opdec 0]
333 set opstorereg [lindex $opdec 4]
334 set opdblflag [lindex $opdec 5]
335 if { $optype eq "st" && ($opdblflag & 1) } {
336 set can_be [list 0 1 0]
337 } elseif { $optype eq "st" } {
338 set can_be [list 1 0 0]
339 } elseif { $optype ne "ld" && $optype ne "atomic" } {
340 # Any single instruction that is not a load or store
341 set can_be [list 0 0 1]
342 }
343 }
344 lappend can_be_arr $can_be
345 }
346 # can_be_arr has at index
347 # - at index 2: previous previous instruction
348 # - at index 1: previous instruction
349 # - at index 0: current instruction
350 set pp_insn [lindex $can_be_arr 2]
351 set p_insn [lindex $can_be_arr 1]
352 set c_insn [lindex $can_be_arr 0]
353 # Sequence A
354 # 1. store of word size or less
355 # 2. any single instruction that is not a load or store
356 # 3. any store instruction
357 if {
358 (
359 $b2bst_seqa_scan &&
360 [lindex $pp_insn 0] &&
361 [lindex $p_insn 2] &&
362 ([lindex $c_insn 0] || [lindex $c_insn 1])
363 ) } {
364 puts "WARNING: Possible sequence matching LEON3FT b2bst errata (sequence A) in function $fnname"
365 print_trace $fnpc $state fnops 1
366 puts ""
367 return 1
368 }
369
370 # Sequence B
371 # 1. any store instruction
372 # 2. store of double word size
373 if {
374 (
375 $b2bst_seqb_scan &&
376 [lindex $p_insn 1] &&
377 ([lindex $c_insn 0] || [lindex $c_insn 1])
378 ) } {
379 puts "WARNING: Possible sequence matching LEON3FT b2bst errata (sequence B) in function $fnname"
380 print_trace $fnpc $state fnops 0
381 puts ""
382 return 1
383 }
384 return 0
385 }
386
387
388 # Main recursive function doing scan
389 # fnname - funcion name
390 # fnpc, fnnpc, PC/nPC of current insn (8-digit hex, 0x prefix) prefix also with A if annulled,
391 # fnarr - array/hash-table, see descr for scan_wholefunc
392 # dpdist - number of SP FPOPs done minimum since last DP FPOP
393 # state - List of 5 last instruction addresses (hex w 0x prefix), special values "?"=unknown "call"=call from calling proc
394 # smap - Hash table used to track where we have been already
395 proc scan_wholefunc_main { fnname fnpc fnnpc fnarr savelevel dpdist state smap lastoptype } {
396 global dslot_mode
397 upvar $fnarr fnops
398 upvar $smap statemap
399
400 set r 0
401
402 # puts "entering scan_wholefunc_main: PC:$fnpc nPC:$fnnpc dpdist:$dpdist savelevel:$savelevel state:$state"
403 # puts "fnops exists [info exists fnops] [array exists fnops] [array names fnops]"
404 while {1} {
405 # puts "scan_wholefunc_main: PC:$fnpc nPC:$fnnpc dpdist:$dpdist savelevel:$savelevel state:$state"
406 set statedesc [list $fnpc $fnnpc $savelevel $dpdist $state]
407 if { [info exists statemap($statedesc)] } {
408 # Already been here
409 return $r
410 }
411 set statemap($statedesc) 1
412
413 set fnpca $fnpc
414 set pcannul 0
415 if { [string index $fnpc 0] eq "A" } {
416 set pcannul 1
417 set fnpc [string range $fnpc 1 end]
418 set ophex "0x01000000"
419 } else {
420 if {![info exists fnops($fnpc)]} {
421 puts_note "$fnname: Execution leaves function without return";
422 return $r
423 }
424
425 set op $fnops($fnpc)
426 set ophex [lindex $op 0]
427 set opname [lindex $op 1]
428 }
429
430 set opdec [ decode_inst $ophex $fnpc $fnnpc ]
431 unpack $opdec optype treg sreg1 sreg2 streg dblflag immed nnpc1 nnpc2 annul bubbles
432
433 set prev_savelevel $savelevel
434 if { $optype eq "fpop" } {
435 # update dpdist
436 if { ($dblflag & 6) == 0 } {
437 if { $dpdist < 2 } { incr dpdist }
438 } else {
439 set dpdist 0
440 }
441 } elseif { $optype eq "save" } {
442 if { $savelevel > 9 } {
443 puts_note "$fnname: More than 10 deep saves (possibly regfile clear loop)"
444 } else {
445 incr savelevel
446 }
447 # puts "save at $fnpc, new savelevel: $savelevel"
448 } elseif { $optype eq "restore" } {
449 if { $savelevel < -9 } {
450 puts_note "$fnname: More than 10 deep restores (possibly regfile clear loop)"
451 } else {
452 if { $savelevel == 0 } {
453 puts_note "$fnname: More restore than save instructions"
454 }
455 set savelevel [ expr { $savelevel-1} ]
456 }
457 # puts "restore at $fnpc, new savelevel: $savelevel"
458 }
459 if { true && ($optype eq "st") } {
460 if { [scan_b2bst $fnname $fnpc $op $opdec fnops $state] } { incr r }
461 }
462
463 # Handle jmpl and call
464 # If in delay slot of jmpl:
465 # If ret or retl, stop recursing further
466 # If other jmpl, check savelevel if it will return or not
467 # If in delay slot of call, set dpdist to 0 (called proc may have done DP operation)
468 set is_call 0
469 if {
470 (
471 $dslot_mode != 0 &&
472 ($lastoptype eq "branch" || $lastoptype eq "jmpl" || $lastoptype eq "call")
473 ) } {
474 if { $optype eq "st" } {
475 puts "WARNING: $fnname: $opname in delay slot of branch/call/ret at $fnpc may cause errata"
476 print_trace $fnpc $state fnops -1 1
477 puts ""
478 incr r
479 }
480 }
481 if { $lastoptype eq "jmpl" } {
482 set linst [lindex $state 0]
483 set q $fnops($linst)
484 set qh [lindex $q 0]
485 set qdec [ decode_inst $qh $linst $fnpc ]
486 unpack $qdec qdtype qdtreg qdsreg1 qdsreg2 qdstreg qddblflag qdimmed qdnnpc1 qdnnpc2 qdannul
487 if { $qdtreg==15 && $prev_savelevel==1 && $savelevel==1 } {
488 # Function call via pointer
489 incr is_call
490 } elseif { $qdtreg==0 && $savelevel==0 } {
491 # Return or tail recursion
492 return $r
493 } else {
494 # Computed goto or some other non-standard construct
495 puts_info "$fnname: Unable to trace jmpl at $linst - check manually"
496 return $r
497 }
498 } elseif { $lastoptype eq "call" } {
499 if { $savelevel==0 && $prev_savelevel==1 } {
500 # call,restore tail recursion into other fn
501 return $r
502 } elseif { $savelevel==0 && $prev_savelevel==0 && $treg == 15 } {
503 puts_note "$fnname: Leaf tail recursion construct at $fnpc"
504 return $r
505 } else {
506 incr is_call
507 }
508 }
509 # Update history
510 for { set z 0 } { $z <= $bubbles } { incr z } {
511 set state [concat $fnpca [lrange $state 0 4] ]
512 }
513 if { $is_call } {
514 if { $optype eq "branch" || $optype eq "call" || $optype eq "jmpl" } {
515 puts_info "$fnname: jump in delay slot of call - check manually"
516 }
517 # Setup state after call has returned
518 set dpdist 0
519 set state [list "dslot" "ret" "ret" "ret" "?" ]
520 set optype "?"; # for lastoptype
521 set fnnpc [ format "0x%08x" [expr {$fnpc+4}]]
522 set nnpc1 [ format "0x%08x" [expr {$fnpc+8}]]
523 set nnpc2 $nnpc1
524 set annul 0
525 }
526 # Handle annullment
527 if { ($annul & 2) != 0 } { set npc1 "A$fnnpc" } else { set npc1 $fnnpc }
528 if { ($annul & 1) != 0 } { set npc2 "A$fnnpc" } else { set npc2 $fnnpc }
529 # Recurse if multiple nPC:s, tail recurse for last element
530 if { $nnpc1 != $nnpc2 || $npc1 != $npc2 } {
531 # puts "Recursion nnpc:$nnpc2!"
532 set q [scan_wholefunc_main $fnname $npc1 $nnpc2 fnops $savelevel $dpdist $state statemap $optype]
533 set r [expr {$r+$q}]
534 }
535 set fnpc $npc1
536 set fnnpc $nnpc1
537 set lastoptype $optype
538 }
539 }
540
541 # Whole function scan for "LEON3FT Stale Cache After Store with Data Tag Parity Error" errata
542 # fnname - function name, fnaddr - function addres
543 # fnarr - name of array/hash-table containing operations
544 # key to the array is the address as 8-digit hex number prefixed with 0x
545 # value is a list containing 0:opcode, 1:mnemonic, 2:args
546 proc scan_wholefunc { fnname fnaddr fnarr } {
547 global fn_count fninst_count;
548 upvar $fnarr fnops
549
550 if { $fnname eq ".text" } {
551 puts "WARNING: The disassembled binary appears to be stripped, the script can not scan stripped binaries"
552 }
553
554 # Does the fn not contain any store at all, then we can skip it
555 set sid [array startsearch fnops]
556 set found_st 0
557 while { !$found_st } {
558 set op [array nextelement fnops $sid]
559 if { $op eq "" } { array donesearch fnops $sid; break }
560 set ophex [lindex $fnops($op) 0]
561 # puts "$ophex"
562 if { [is_store $ophex] } { incr found_st }
563 }
564 if { !$found_st } {
565 # puts "No store in $fnname!"
566 return 0
567 }
568
569 # -- Function contains store, proceed with scanning
570 # puts "Checking $fnname"
571 set pc "0x$fnaddr"
572 # puts "pc: $pc"
573 set npc [format "0x%08x" [expr {$pc+4}]]
574 array unset statemap
575 array set statemap ""
576 set ec [scan_wholefunc_main $fnname $pc $npc fnops 0 0 [list "dslot" "call" "?" "?" "?" "?"] statemap "?"]
577 # Update fn_count/fninst_count
578 incr fn_count
579 array unset itagchk
580 array set itagchk ""
581 set sid [array startsearch statemap]
582 while { [array anymore statemap $sid] } {
583 set x [array nextelement statemap $sid]
584 set iaddr [lindex $x 0]
585 # puts "iaddr: $iaddr"
586 if { [info exists fnops($iaddr)] && ![info exists itagchk($iaddr)]} {
587 incr fninst_count
588 set itagchk($iaddr) 1
589 }
590 }
591 array donesearch statemap $sid
592 return $ec
593 }
594
595
596 # --------- Main routine
597
598 if { ! [info exists sourcing] } {
599
600 # Parse command line
601 for {set i 0} {$i < $argc} {incr i} {
602 set arg [lindex $argv $i]
603 puts "arg=$arg"
604 if {"-noinfo" eq $arg} {
605 set msglevel [expr {$msglevel & ~($MSG_INFO)}]
606 }
607 if {"-nonote" eq $arg} {
608 set msglevel [expr {$msglevel & ~($MSG_NOTE)}]
609 }
610 if {"-silent" eq $arg} {
611 set msglevel 0
612 }
613 }
614
615 puts "\n$errata_desc errata scanning utility, rev $util_rev ($util_date)"
616
617 puts "Searching objdump -d output on standard input for:"
618 if {$b2bst_seqa_scan} {
619 puts " - $b2bst_seqa_desc"
620 }
621 if {$b2bst_seqb_scan} {
622 puts " - $b2bst_seqb_desc"
623 }
624 puts ""
625
626 set fn_valid 0
627 while {! [eof stdin]} {
628 set l [gets stdin]
629 incr line_count
630 # puts "line $l"
631 # Remove comment after '!'
632 set x [string first "!" "$l"]
633 if { $x >= 0 } then { set l [string range "$l" 0 $x] }
634 # check if entry point / function start
635 set m [regexp {^ *([0-9A-Fa-f]+) <([^ ]+)>:} "$l" t1 addr symname]
636 if { $m > 0 } then {
637 # puts "Function name=$symname addr=$addr"
638 if { $fn_valid } {
639 # puts $curfn_ops(0x40000000)
640 set q [scan_wholefunc $curfn $curfn_addr curfn_ops]
641 # puts "q=$q err_count=$err_count"
642 set err_count [ expr { $err_count + $q } ]
643 }
644 set curfn "$symname"
645 set curfn_addr "$addr"
646 array unset curfn_ops
647 array set curfn_ops ""
648 set fn_valid 0
649 } else {
650 # Check if opcode
651 set m [regexp {^ *([0-9A-Fa-f]+): *\t(.. .. .. ..) *\t([^ ]+)(.*)$} "$l" t1 addr hexcode opname opargs]
652 if { $m > 0 } then {
653 # puts "Opcode name=$opname args=$opargs addr=$addr"
654 incr op_count
655 set addr [format "%08x" 0x$addr]
656 set hexcode [string map {" " ""} $hexcode]
657 # puts "setting curfn_ops 0x$addr"
658 set curfn_ops(0x$addr) [list "0x$hexcode" $opname $opargs "" ""]
659 incr fn_valid
660 } else {
661 incr lineskip_count
662 }
663 }
664 }
665 if { $fn_valid } {
666 set q [scan_wholefunc $curfn $curfn_addr curfn_ops]
667 set err_count [ expr { $err_count + $q } ]
668 }
669
670 puts "\nObjdump lines processed: $line_count, lines skipped: $lineskip_count"
671 puts "Functions scanned: ${fn_count}, reachable instruction count: ${fninst_count}"
672 puts "Potential error locations found: $err_count\n"
673
674 if {$err_count == 0} {
675 exit 0
676 } else {
677 exit 1
678 }
679
680 }
681
@@ -1,2068 +1,2068
1 1 /** Functions to load and dump parameters in the LFR registers.
2 2 *
3 3 * @file
4 4 * @author P. LEROY
5 5 *
6 6 * A group of functions to handle TC related to parameter loading and dumping.\n
7 7 * TC_LFR_LOAD_COMMON_PAR\n
8 8 * TC_LFR_LOAD_NORMAL_PAR\n
9 9 * TC_LFR_LOAD_BURST_PAR\n
10 10 * TC_LFR_LOAD_SBM1_PAR\n
11 11 * TC_LFR_LOAD_SBM2_PAR\n
12 12 *
13 13 */
14 14
15 15 #include "tc_load_dump_parameters.h"
16 16
17 17 Packet_TM_LFR_KCOEFFICIENTS_DUMP_t kcoefficients_dump_1 = {0};
18 18 Packet_TM_LFR_KCOEFFICIENTS_DUMP_t kcoefficients_dump_2 = {0};
19 19 ring_node kcoefficient_node_1 = {0};
20 20 ring_node kcoefficient_node_2 = {0};
21 21
22 22 int action_load_common_par(ccsdsTelecommandPacket_t *TC)
23 23 {
24 24 /** This function updates the LFR registers with the incoming common parameters.
25 25 *
26 26 * @param TC points to the TeleCommand packet that is being processed
27 27 *
28 28 *
29 29 */
30 30
31 31 parameter_dump_packet.sy_lfr_common_parameters_spare = TC->dataAndCRC[0];
32 32 parameter_dump_packet.sy_lfr_common_parameters = TC->dataAndCRC[1];
33 33 set_wfp_data_shaping( );
34 34 return LFR_SUCCESSFUL;
35 35 }
36 36
37 37 int action_load_normal_par(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
38 38 {
39 39 /** This function updates the LFR registers with the incoming normal parameters.
40 40 *
41 41 * @param TC points to the TeleCommand packet that is being processed
42 42 * @param queue_id is the id of the queue which handles TM related to this execution step
43 43 *
44 44 */
45 45
46 46 int result;
47 47 int flag;
48 48 rtems_status_code status;
49 49
50 50 flag = LFR_SUCCESSFUL;
51 51
52 52 if ( (lfrCurrentMode == LFR_MODE_NORMAL) ||
53 53 (lfrCurrentMode == LFR_MODE_SBM1) || (lfrCurrentMode == LFR_MODE_SBM2) ) {
54 54 status = send_tm_lfr_tc_exe_not_executable( TC, queue_id );
55 55 flag = LFR_DEFAULT;
56 56 }
57 57
58 58 // CHECK THE PARAMETERS SET CONSISTENCY
59 59 if (flag == LFR_SUCCESSFUL)
60 60 {
61 61 flag = check_normal_par_consistency( TC, queue_id );
62 62 }
63 63
64 64 // SET THE PARAMETERS IF THEY ARE CONSISTENT
65 65 if (flag == LFR_SUCCESSFUL)
66 66 {
67 67 result = set_sy_lfr_n_swf_l( TC );
68 68 result = set_sy_lfr_n_swf_p( TC );
69 69 result = set_sy_lfr_n_bp_p0( TC );
70 70 result = set_sy_lfr_n_bp_p1( TC );
71 71 result = set_sy_lfr_n_asm_p( TC );
72 72 result = set_sy_lfr_n_cwf_long_f3( TC );
73 73 }
74 74
75 75 return flag;
76 76 }
77 77
78 78 int action_load_burst_par(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
79 79 {
80 80 /** This function updates the LFR registers with the incoming burst parameters.
81 81 *
82 82 * @param TC points to the TeleCommand packet that is being processed
83 83 * @param queue_id is the id of the queue which handles TM related to this execution step
84 84 *
85 85 */
86 86
87 87 int flag;
88 88 rtems_status_code status;
89 89 unsigned char sy_lfr_b_bp_p0;
90 90 unsigned char sy_lfr_b_bp_p1;
91 91 float aux;
92 92
93 93 flag = LFR_SUCCESSFUL;
94 94
95 95 if ( lfrCurrentMode == LFR_MODE_BURST ) {
96 96 status = send_tm_lfr_tc_exe_not_executable( TC, queue_id );
97 97 flag = LFR_DEFAULT;
98 98 }
99 99
100 100 sy_lfr_b_bp_p0 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_B_BP_P0 ];
101 101 sy_lfr_b_bp_p1 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_B_BP_P1 ];
102 102
103 103 // sy_lfr_b_bp_p0 shall not be lower than its default value
104 104 if (flag == LFR_SUCCESSFUL)
105 105 {
106 106 if (sy_lfr_b_bp_p0 < DEFAULT_SY_LFR_B_BP_P0 )
107 107 {
108 108 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_B_BP_P0 + DATAFIELD_OFFSET, sy_lfr_b_bp_p0 );
109 109 flag = WRONG_APP_DATA;
110 110 }
111 111 }
112 112 // sy_lfr_b_bp_p1 shall not be lower than its default value
113 113 if (flag == LFR_SUCCESSFUL)
114 114 {
115 115 if (sy_lfr_b_bp_p1 < DEFAULT_SY_LFR_B_BP_P1 )
116 116 {
117 117 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_B_BP_P1 + DATAFIELD_OFFSET, sy_lfr_b_bp_p1 );
118 118 flag = WRONG_APP_DATA;
119 119 }
120 120 }
121 121 //****************************************************************
122 122 // check the consistency between sy_lfr_b_bp_p0 and sy_lfr_b_bp_p1
123 123 if (flag == LFR_SUCCESSFUL)
124 124 {
125 125 sy_lfr_b_bp_p0 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_B_BP_P0 ];
126 126 sy_lfr_b_bp_p1 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_B_BP_P1 ];
127 127 aux = ( (float ) sy_lfr_b_bp_p1 / sy_lfr_b_bp_p0 ) - floor(sy_lfr_b_bp_p1 / sy_lfr_b_bp_p0);
128 128 if (aux > FLOAT_EQUAL_ZERO)
129 129 {
130 130 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_B_BP_P0 + DATAFIELD_OFFSET, sy_lfr_b_bp_p0 );
131 131 flag = LFR_DEFAULT;
132 132 }
133 133 }
134 134
135 135 // SET THE PARAMETERS
136 136 if (flag == LFR_SUCCESSFUL)
137 137 {
138 138 flag = set_sy_lfr_b_bp_p0( TC );
139 139 flag = set_sy_lfr_b_bp_p1( TC );
140 140 }
141 141
142 142 return flag;
143 143 }
144 144
145 145 int action_load_sbm1_par(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
146 146 {
147 147 /** This function updates the LFR registers with the incoming sbm1 parameters.
148 148 *
149 149 * @param TC points to the TeleCommand packet that is being processed
150 150 * @param queue_id is the id of the queue which handles TM related to this execution step
151 151 *
152 152 */
153 153
154 154 int flag;
155 155 rtems_status_code status;
156 156 unsigned char sy_lfr_s1_bp_p0;
157 157 unsigned char sy_lfr_s1_bp_p1;
158 158 float aux;
159 159
160 160 flag = LFR_SUCCESSFUL;
161 161
162 162 if ( lfrCurrentMode == LFR_MODE_SBM1 ) {
163 163 status = send_tm_lfr_tc_exe_not_executable( TC, queue_id );
164 164 flag = LFR_DEFAULT;
165 165 }
166 166
167 167 sy_lfr_s1_bp_p0 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_S1_BP_P0 ];
168 168 sy_lfr_s1_bp_p1 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_S1_BP_P1 ];
169 169
170 170 // sy_lfr_s1_bp_p0
171 171 if (flag == LFR_SUCCESSFUL)
172 172 {
173 173 if (sy_lfr_s1_bp_p0 < DEFAULT_SY_LFR_S1_BP_P0 )
174 174 {
175 175 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_S1_BP_P0 + DATAFIELD_OFFSET, sy_lfr_s1_bp_p0 );
176 176 flag = WRONG_APP_DATA;
177 177 }
178 178 }
179 179 // sy_lfr_s1_bp_p1
180 180 if (flag == LFR_SUCCESSFUL)
181 181 {
182 182 if (sy_lfr_s1_bp_p1 < DEFAULT_SY_LFR_S1_BP_P1 )
183 183 {
184 184 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_S1_BP_P1 + DATAFIELD_OFFSET, sy_lfr_s1_bp_p1 );
185 185 flag = WRONG_APP_DATA;
186 186 }
187 187 }
188 188 //******************************************************************
189 189 // check the consistency between sy_lfr_s1_bp_p0 and sy_lfr_s1_bp_p1
190 190 if (flag == LFR_SUCCESSFUL)
191 191 {
192 192 aux = ( (float ) sy_lfr_s1_bp_p1 / (sy_lfr_s1_bp_p0 * S1_BP_P0_SCALE) )
193 193 - floor(sy_lfr_s1_bp_p1 / (sy_lfr_s1_bp_p0 * S1_BP_P0_SCALE));
194 194 if (aux > FLOAT_EQUAL_ZERO)
195 195 {
196 196 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_S1_BP_P0 + DATAFIELD_OFFSET, sy_lfr_s1_bp_p0 );
197 197 flag = LFR_DEFAULT;
198 198 }
199 199 }
200 200
201 201 // SET THE PARAMETERS
202 202 if (flag == LFR_SUCCESSFUL)
203 203 {
204 204 flag = set_sy_lfr_s1_bp_p0( TC );
205 205 flag = set_sy_lfr_s1_bp_p1( TC );
206 206 }
207 207
208 208 return flag;
209 209 }
210 210
211 211 int action_load_sbm2_par(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
212 212 {
213 213 /** This function updates the LFR registers with the incoming sbm2 parameters.
214 214 *
215 215 * @param TC points to the TeleCommand packet that is being processed
216 216 * @param queue_id is the id of the queue which handles TM related to this execution step
217 217 *
218 218 */
219 219
220 220 int flag;
221 221 rtems_status_code status;
222 222 unsigned char sy_lfr_s2_bp_p0;
223 223 unsigned char sy_lfr_s2_bp_p1;
224 224 float aux;
225 225
226 226 flag = LFR_SUCCESSFUL;
227 227
228 228 if ( lfrCurrentMode == LFR_MODE_SBM2 ) {
229 229 status = send_tm_lfr_tc_exe_not_executable( TC, queue_id );
230 230 flag = LFR_DEFAULT;
231 231 }
232 232
233 233 sy_lfr_s2_bp_p0 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_S2_BP_P0 ];
234 234 sy_lfr_s2_bp_p1 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_S2_BP_P1 ];
235 235
236 236 // sy_lfr_s2_bp_p0
237 237 if (flag == LFR_SUCCESSFUL)
238 238 {
239 239 if (sy_lfr_s2_bp_p0 < DEFAULT_SY_LFR_S2_BP_P0 )
240 240 {
241 241 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_S2_BP_P0 + DATAFIELD_OFFSET, sy_lfr_s2_bp_p0 );
242 242 flag = WRONG_APP_DATA;
243 243 }
244 244 }
245 245 // sy_lfr_s2_bp_p1
246 246 if (flag == LFR_SUCCESSFUL)
247 247 {
248 248 if (sy_lfr_s2_bp_p1 < DEFAULT_SY_LFR_S2_BP_P1 )
249 249 {
250 250 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_S2_BP_P1 + DATAFIELD_OFFSET, sy_lfr_s2_bp_p1 );
251 251 flag = WRONG_APP_DATA;
252 252 }
253 253 }
254 254 //******************************************************************
255 255 // check the consistency between sy_lfr_s2_bp_p0 and sy_lfr_s2_bp_p1
256 256 if (flag == LFR_SUCCESSFUL)
257 257 {
258 258 sy_lfr_s2_bp_p0 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_S2_BP_P0 ];
259 259 sy_lfr_s2_bp_p1 = TC->dataAndCRC[ DATAFIELD_POS_SY_LFR_S2_BP_P1 ];
260 260 aux = ( (float ) sy_lfr_s2_bp_p1 / sy_lfr_s2_bp_p0 ) - floor(sy_lfr_s2_bp_p1 / sy_lfr_s2_bp_p0);
261 261 if (aux > FLOAT_EQUAL_ZERO)
262 262 {
263 263 status = send_tm_lfr_tc_exe_inconsistent( TC, queue_id, DATAFIELD_POS_SY_LFR_S2_BP_P0 + DATAFIELD_OFFSET, sy_lfr_s2_bp_p0 );
264 264 flag = LFR_DEFAULT;
265 265 }
266 266 }
267 267
268 268 // SET THE PARAMETERS
269 269 if (flag == LFR_SUCCESSFUL)
270 270 {
271 271 flag = set_sy_lfr_s2_bp_p0( TC );
272 272 flag = set_sy_lfr_s2_bp_p1( TC );
273 273 }
274 274
275 275 return flag;
276 276 }
277 277
278 278 int action_load_kcoefficients(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
279 279 {
280 280 /** This function updates the LFR registers with the incoming sbm2 parameters.
281 281 *
282 282 * @param TC points to the TeleCommand packet that is being processed
283 283 * @param queue_id is the id of the queue which handles TM related to this execution step
284 284 *
285 285 */
286 286
287 287 int flag;
288 288
289 289 flag = LFR_DEFAULT;
290 290
291 291 flag = set_sy_lfr_kcoeff( TC, queue_id );
292 292
293 293 return flag;
294 294 }
295 295
296 296 int action_load_fbins_mask(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
297 297 {
298 298 /** This function updates the LFR registers with the incoming sbm2 parameters.
299 299 *
300 300 * @param TC points to the TeleCommand packet that is being processed
301 301 * @param queue_id is the id of the queue which handles TM related to this execution step
302 302 *
303 303 */
304 304
305 305 int flag;
306 306
307 307 flag = LFR_DEFAULT;
308 308
309 309 flag = set_sy_lfr_fbins( TC );
310 310
311 311 // once the fbins masks have been stored, they have to be merged with the masks which handle the reaction wheels frequencies filtering
312 312 merge_fbins_masks();
313 313
314 314 return flag;
315 315 }
316 316
317 317 int action_load_filter_par(ccsdsTelecommandPacket_t *TC, rtems_id queue_id, unsigned char *time)
318 318 {
319 319 /** This function updates the LFR registers with the incoming sbm2 parameters.
320 320 *