3 # NOTE that this program is python2 compatible, please do not stop it
4 # from working by adding syntax that prevents that.
6 # Initial version written by lkcl Oct 2020
7 # This program analyses the Power 9 op codes and looks at in/out register uses
8 # The results are displayed:
9 # https://libre-soc.org/openpower/opcode_regs_deduped/
11 # It finds .csv files in the directory isatables/
12 # then goes through the categories and creates svp64 CSV augmentation
13 # tables on a per-opcode basis
15 # NOTE: this program is effectively part of the Simple-V Specification.
16 # it encapsulates the relationships of what can be SVP64-encoded and
17 # holds all of the information on how to encode and decode SVP64.
18 # By auto-generating tables that go into the Simple-V Specification
19 # this program *is* the specification. do not be confused just because
20 # it is in python: if you do not understand please ask questions and
21 # help create patches with explanatory comments.
27 from os
.path
import dirname
, join
29 from collections
import defaultdict
30 from collections
import OrderedDict
31 from openpower
.decoder
.power_svp64
import SVP64RM
32 from openpower
.decoder
.power_enums
import find_wiki_file
, get_csv
33 from openpower
.util
import log
36 # Ignore those containing: valid test sprs
37 def glob_valid_csvs(root
):
39 _
, name
= os
.path
.split(fname
)
46 if fname
.endswith('insndb.csv'):
48 if fname
.endswith('sprs.csv'):
50 if fname
.endswith('minor_19_valid.csv'):
56 yield from filter(check_csv
, glob(root
))
59 # Write an array of dictionaries to the CSV file name:
60 def write_csv(name
, items
, headers
):
61 file_path
= find_wiki_file(name
)
62 with
open(file_path
, 'w') as csvfile
:
63 writer
= csv
.DictWriter(csvfile
, headers
, lineterminator
="\n")
65 writer
.writerows(items
)
67 # This will return True if all values are true.
68 # Not sure what this is about
72 # for v in row.values():
73 # if 'SPR' in v: # skip all SPRs
75 for v
in row
.values():
80 # General purpose registers have names like: RA, RT, R1, ...
81 # Floating point registers names like: FRT, FRA, FR1, ..., FRTp, ...
82 # Return True if field is a register
86 return (field
.startswith('R') or field
.startswith('FR') or
90 # These are the attributes of the instructions,
92 keycolumns
= ['unit', 'in1', 'in2', 'in3', 'out', 'CR in', 'CR out',
93 ] # don't think we need these: 'ldst len', 'rc', 'lk']
95 tablecols
= ['unit', 'in', 'outcnt', 'CR in', 'CR out', 'imm'
96 ] # don't think we need these: 'ldst len', 'rc', 'lk']
100 """ create an equivalent of a database key by which it is possible
101 to easily categorise an instruction. later this category is used
102 to decide what kind of EXTRA encoding is to be done because the
103 key contains the total number of input and output registers
107 for key
in keycolumns
:
108 # registers IN - special-case: count number of regs RA/RB/RC/RS
109 if key
in ['in1', 'in2', 'in3']:
112 if row
['unit'] == 'BRANCH': # branches must not include Vector SPRs
119 # If upd is 1 then increment the count of outputs
120 if 'outcnt' not in res
:
124 if row
['upd'] == '1':
127 # CRs (Condition Register) (CR0 .. CR7)
128 if key
.startswith('CR'):
129 if row
[key
].startswith('NONE'):
133 if row
['comment'].startswith('cr'):
137 if row
[key
] == 'LDST': # we care about LDST units
141 # LDST len (LoadStore length)
142 if key
.startswith('ldst'):
143 if row
[key
].startswith('NONE'):
148 if key
in ['rc', 'lk']:
149 if row
[key
] == 'ONE':
151 elif row
[key
] == 'NONE':
158 # Convert the numerics 'in' & 'outcnt' to strings
159 res
['in'] = str(res
['in'])
160 res
['outcnt'] = str(res
['outcnt'])
163 if row
['in2'].startswith('CONST_'):
164 res
['imm'] = "1" # row['in2'].split("_")[1]
175 for k
, v
in d
.items():
176 res
.append("%s: %s" % (k
, v
))
181 return "| " + ' | '.join(d
) + " |"
185 """converts a key into a readable string. anything null or zero
186 is skipped, shortening the readable string
189 if row
['unit'] != 'OTHER':
190 res
.append(row
['unit'])
192 res
.append('%sR' % row
['in'])
193 if row
['outcnt'] != '0':
194 res
.append('%sW' % row
['outcnt'])
195 if row
['CR in'] == '1' and row
['CR out'] == '1':
197 res
.append("CR=2R1W")
200 elif row
['CR in'] == '1':
202 elif row
['CR out'] == '1':
204 elif 'imm' in row
and row
['imm']:
209 class Format(enum
.Enum
):
210 BINUTILS
= enum
.auto()
214 def _missing_(cls
, value
):
216 "binutils": Format
.BINUTILS
,
221 return self
.name
.lower()
223 def declarations(self
, values
, lens
):
224 def declaration_binutils(value
, width
):
225 yield f
"/* TODO: implement binutils declaration (value={value!r}, width={width!r}) */"
227 def declaration_vhdl(value
, width
):
228 yield f
" type sv_{value}_rom_array_t is " \
229 f
"array(0 to {width}) of sv_decode_rom_t;"
232 if value
not in lens
:
233 todo
= [f
"TODO {value} (or no SVP64 augmentation)"]
234 todo
= self
.wrap_comment(todo
)
235 yield from map(lambda line
: f
" {line}", todo
)
239 Format
.BINUTILS
: declaration_binutils
,
240 Format
.VHDL
: declaration_vhdl
,
241 }[self
](value
, width
)
243 def definitions(self
, entries_svp64
, fullcols
):
244 def definitions_vhdl():
245 for (value
, entries
) in entries_svp64
.items():
247 yield f
" constant sv_{value}_decode_rom_array :"
248 yield f
" sv_{value}_rom_array_t := ("
249 yield f
" -- {' '.join(fullcols)}"
251 for (op
, insn
, row
) in entries
:
252 yield f
" {op:>13} => ({', '.join(row)}), -- {insn}"
254 yield f
" {'others':>13} => sv_illegal_inst"
258 def definitions_binutils():
259 yield f
"/* TODO: implement binutils definitions */"
262 Format
.BINUTILS
: definitions_binutils
,
263 Format
.VHDL
: definitions_vhdl
,
266 def wrap_comment(self
, lines
):
267 def wrap_comment_binutils(lines
):
270 yield f
"/* {lines[0]} */"
273 yield from map(lambda line
: f
" * {line}", lines
)
276 def wrap_comment_vhdl(lines
):
277 yield from map(lambda line
: f
"-- {line}", lines
)
280 Format
.BINUTILS
: wrap_comment_binutils
,
281 Format
.VHDL
: wrap_comment_vhdl
,
290 dictkeys
= OrderedDict()
292 insns
= {} # dictionary of CSV row, by instruction
295 # Expand that (all .csv files)
296 pth
= find_wiki_file("*.csv")
298 # Ignore those containing: valid test sprs
299 for fname
in glob_valid_csvs(pth
):
300 csvname
= os
.path
.split(fname
)[1]
301 csvname_
= csvname
.split(".")[0]
302 # csvname is something like: minor_59.csv, fname the whole path
305 csvs_svp64
[csvname_
] = []
310 insn_name
= row
['comment']
311 condition
= row
['CONDITIONS']
312 # skip instructions that are not suitable
313 if insn_name
.startswith("l") and insn_name
.endswith("br"):
314 continue # skip pseudo-alias lxxxbr
315 if insn_name
in ['mcrxr', 'mcrxrx', 'darn']:
317 if insn_name
in ['bctar', 'bcctr']:
319 if 'rfid' in insn_name
:
321 if insn_name
in ['setvl', ]: # SVP64 opcodes
324 insns
[(insn_name
, condition
)] = row
# accumulate csv data
325 insn_to_csv
[insn_name
] = csvname_
# CSV file name by instruction
326 dkey
= create_key(row
)
327 key
= tuple(dkey
.values())
328 #print("key=", key, dkey)
333 bykey
[key
].append((csvname
, row
['opcode'], insn_name
, condition
,
334 row
['form'].upper() + '-Form'))
336 # detect immediates, collate them (useful info)
337 if row
['in2'].startswith('CONST_'):
338 imm
= row
['in2'].split("_")[1]
339 if key
not in immediates
:
340 immediates
[key
] = set()
341 immediates
[key
].add(imm
)
343 primarykeys
= list(primarykeys
)
346 return (csvs
, csvs_svp64
, primarykeys
, bykey
, insn_to_csv
, insns
,
347 dictkeys
, immediates
)
350 def regs_profile(insn
, res
):
351 """get a more detailed register profile: 1st operand is RA,
355 for k
in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
356 if insn
[k
].startswith('CONST'):
361 if insn
[k
] == 'RA_OR_ZERO':
363 elif insn
[k
] != 'NONE':
370 def extra_classifier(insn_name
, value
, name
, res
, regs
):
371 """extra_classifier: creates the SVP64.RM EXTRA2/3 classification.
372 there is very little space (9 bits) to mark register operands
373 (RT RA RB, BA BB, BFA, FRS etc.) with the "extra" information
374 needed to tell if *EACH* operand (of which there can be up to five!)
375 is Vectorised, and whether its numbering is extended into the
376 0..127 range rather than the limited 3/5 bit of Scalar v3.0 Power ISA.
378 thus begins the rather tedious but by-rote examination of EVERY
379 Scalar instruction, working out how best to tell a decoder how to
380 extend the registers. EXTRA2 can have up to 4 slots (of 2 bit each)
381 where due to RM.EXTRA being 9 bits, EXTRA3 can have up to 3 slots
382 (of 3 bit each). the index REGNAME says which slot the register
383 named REGNAME must read its decoding from. d: means destination,
384 s: means source. some are *shared slots* especially LDST update.
385 some Rc=1 ops have the CR0/CR1 as a co-result which is also
386 obviously Vectorised if the result is Vectorised.
388 it is actually quite straightforward but the sheer quantity of
389 Scalar Power ISA instructions made it prudent to do this in an
390 intelligent way, almost by-rote, by analysing the register profiles.
392 # for LD/ST FP, use FRT/FRS not RT/RS, and use CR1 not CR0
393 if insn_name
.startswith("lf"):
399 if insn_name
.startswith("stf"):
406 # sigh now the fun begins. this isn't the sanest way to do it
407 # but the patterns are pretty regular. we start with the "profile"
408 # because that determines how much space is available (total num
409 # regs to decode) then if necessary begin apecialising either
410 # by the instruction name or through more detailed register
411 # profiling. example:
412 # if regs == ['RA', '', '', 'RT', '', '']:
413 # is in the order in1 in2 in3 out1 out2 Rc=1
418 if value
== 'LDSTRM-2P-1S1D':
419 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
420 res
['0'] = dRT
# RT: Rdest_EXTRA3
421 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
423 elif value
== 'LDSTRM-2P-1S2D':
424 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
425 res
['0'] = dRT
# RT: Rdest_EXTRA3
426 res
['1'] = 'd:RA' # RA: Rdest2_EXTRA2
427 res
['2'] = 's:RA' # RA: Rsrc1_EXTRA2
429 elif value
== 'LDSTRM-2P-2S':
431 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
432 res
['0'] = sRS
# RS: Rdest1_EXTRA3
433 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
435 elif value
== 'LDSTRM-2P-2S1D':
436 if 'st' in insn_name
and 'x' not in insn_name
: # stwu/stbu etc
437 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
438 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA2
439 res
['1'] = sRS
# RS: Rdsrc1_EXTRA2
440 res
['2'] = 's:RA' # RA: Rsrc2_EXTRA2
441 elif 'st' in insn_name
and 'x' in insn_name
: # stwux
442 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
443 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA2
444 # RS: Rdest2_EXTRA2, RA: Rsrc1_EXTRA2
445 res
['1'] = "%s;%s" % (sRS
, 's:RA')
446 res
['2'] = 's:RB' # RB: Rsrc2_EXTRA2
447 elif 'u' in insn_name
: # ldux etc.
448 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
449 res
['0'] = dRT
# RT: Rdest1_EXTRA2
450 res
['1'] = 'd:RA' # RA: Rdest2_EXTRA2
451 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA2
453 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
454 res
['0'] = dRT
# RT: Rdest1_EXTRA2
455 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
456 res
['2'] = 's:RB' # RB: Rsrc2_EXTRA2
458 elif value
== 'LDSTRM-2P-3S':
459 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
460 if 'cx' in insn_name
:
461 res
['0'] = "%s;%s" % (sRS
, dCR
) # RS: Rsrc1_EXTRA2 CR0: dest
463 res
['0'] = sRS
# RS: Rsrc1_EXTRA2
464 res
['1'] = 's:RA' # RA: Rsrc2_EXTRA2
465 res
['2'] = 's:RB' # RA: Rsrc3_EXTRA2
468 # now begins,arithmetic
470 elif value
== 'RM-2P-1S1D':
471 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
472 if insn_name
== 'mtspr':
473 res
['0'] = 'd:SPR' # SPR: Rdest1_EXTRA3
474 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
475 elif insn_name
== 'mfspr':
476 res
['0'] = 'd:RS' # RS: Rdest1_EXTRA3
477 res
['1'] = 's:SPR' # SPR: Rsrc1_EXTRA3
478 elif name
== 'CRio' and insn_name
== 'mcrf':
479 res
['0'] = 'd:BF' # BFA: Rdest1_EXTRA3
480 res
['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
481 elif 'mfcr' in insn_name
or 'mfocrf' in insn_name
:
482 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
483 res
['1'] = 's:CR' # CR: Rsrc1_EXTRA3
484 elif insn_name
== 'setb':
485 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
486 res
['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
487 elif insn_name
.startswith('cmp'): # cmpi
488 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
489 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
490 elif regs
== ['RA', '', '', 'RT', '', '']:
491 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
492 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
493 elif regs
== ['RA', '', '', 'RT', '', 'CR0']:
494 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
495 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
496 elif (regs
== ['RS', '', '', 'RA', '', 'CR0'] or
497 regs
== ['', '', 'RS', 'RA', '', 'CR0']):
498 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
499 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
500 elif regs
== ['RS', '', '', 'RA', '', '']:
501 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA3
502 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
503 elif regs
== ['', 'FRB', '', 'FRT', '0', 'CR1']:
504 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
505 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
506 elif regs
== ['', 'FRB', '', '', '', 'CR1']:
507 res
['0'] = 'd:CR1' # CR1: Rdest1_EXTRA3
508 res
['1'] = 's:FRB' # FRA: Rsrc1_EXTRA3
509 elif regs
== ['', 'FRB', '', '', '', 'BF']:
510 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
511 res
['1'] = 's:FRB' # FRA: Rsrc1_EXTRA3
512 elif regs
== ['', 'FRB', '', 'FRT', '', 'CR1']:
513 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
514 res
['1'] = 's:FRB' # FRB: Rsrc1_EXTRA3
515 elif insn_name
.startswith('bc'):
516 res
['0'] = 'd:BI' # BI: Rdest1_EXTRA3
517 res
['1'] = 's:BI' # BI: Rsrc1_EXTRA3
518 elif insn_name
== 'fishmv':
519 # an overwrite ibstruction
520 res
['0'] = 'd:FRS' # FRS: Rdest1_EXTRA3
521 res
['1'] = 's:FRS' # FRS: Rsrc1_EXTRA3
524 print("regs TODO", insn_name
, regs
)
526 elif value
== 'RM-1P-2S1D':
527 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
528 if insn_name
.startswith('cr'):
529 res
['0'] = 'd:BT' # BT: Rdest1_EXTRA3
530 res
['1'] = 's:BA' # BA: Rsrc1_EXTRA3
531 res
['2'] = 's:BB' # BB: Rsrc2_EXTRA3
532 elif regs
== ['FRA', '', 'FRC', 'FRT', '', 'CR1']:
533 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
534 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
535 res
['2'] = 's:FRC' # FRC: Rsrc1_EXTRA3
537 elif regs
== ['FRA', 'FRB', '', '', '', 'BF']:
538 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
539 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
540 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
541 elif regs
== ['FRA', 'FRB', '', 'FRT', '', '']:
542 res
['0'] = 'd:FRT' # FRT: Rdest1_EXTRA3
543 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
544 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
545 elif regs
== ['FRA', 'FRB', '', 'FRT', '', 'CR1']:
546 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
547 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
548 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
549 elif name
== '2R-1W' or insn_name
== 'cmpb': # cmpb
550 if insn_name
in ['bpermd', 'cmpb']:
551 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA3
552 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
554 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
555 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
556 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
557 elif insn_name
.startswith('cmp'): # cmp
558 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
559 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
560 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
561 elif (regs
== ['', 'RB', 'RS', 'RA', '', 'CR0'] or
562 regs
== ['RS', 'RB', '', 'RA', '', 'CR0']):
563 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
564 res
['1'] = 's:RB' # RB: Rsrc1_EXTRA3
565 res
['2'] = 's:RS' # RS: Rsrc1_EXTRA3
566 elif regs
== ['RA', 'RB', '', 'RT', '', 'CR0']:
567 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
568 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
569 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
570 elif regs
== ['RA', '', 'RS', 'RA', '', 'CR0']:
571 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
572 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
573 res
['2'] = 's:RS' # RS: Rsrc1_EXTRA3
577 elif value
== 'RM-2P-2S1D':
578 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
579 if insn_name
.startswith('mt'): # mtcrf
580 res
['0'] = 'd:CR' # CR: Rdest1_EXTRA2
581 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA2
582 res
['2'] = 's:CR' # CR: Rsrc2_EXTRA2
586 elif value
== 'RM-1P-3S1D':
587 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
588 if regs
== ['RA', 'RB', 'RT', 'RT', '', 'CR0']:
589 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA2
590 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
591 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
592 res
['3'] = 's:RT' # RT: Rsrc3_EXTRA2
593 elif insn_name
== 'isel':
594 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA2
595 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
596 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
597 res
['3'] = 's:BC' # BC: Rsrc3_EXTRA2
599 res
['0'] = 'd:FRT;d:CR1' # FRT, CR1: Rdest1_EXTRA2
600 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA2
601 res
['2'] = 's:FRB' # FRB: Rsrc2_EXTRA2
602 res
['3'] = 's:FRC' # FRC: Rsrc3_EXTRA2
604 elif value
== 'RM-1P-1D':
605 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
606 if insn_name
== 'svstep':
607 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
608 if insn_name
== 'fmvis':
609 res
['0'] = 'd:FRS' # FRS: Rdest1_EXTRA3
612 def process_csvs(format
):
614 print("# Draft SVP64 Power ISA register 'profile's")
616 print("this page is auto-generated, do not edit")
617 print("created by http://libre-soc.org/openpower/sv_analysis.py")
620 (csvs
, csvs_svp64
, primarykeys
, bykey
, insn_to_csv
, insns
,
621 dictkeys
, immediates
) = read_csvs()
623 # mapping to old SVPrefix "Forms"
624 mapsto
= {'3R-1W-CRo': 'RM-1P-3S1D',
625 '2R-1W-CRio': 'RM-1P-2S1D',
626 '2R-1W-CRi': 'RM-1P-3S1D',
627 '2R-1W-CRo': 'RM-1P-2S1D',
629 '2R-1W': 'RM-1P-2S1D',
630 '1R-CRio': 'RM-2P-2S1D',
631 '2R-CRio': 'RM-1P-2S1D',
632 '2R-CRo': 'RM-1P-2S1D',
634 '1R-1W-CRio': 'RM-2P-1S1D',
635 '1R-1W-CRo': 'RM-2P-1S1D',
636 '1R-1W': 'RM-2P-1S1D',
637 '1R-1W-imm': 'RM-2P-1S1D',
638 '1R-CRo': 'RM-2P-1S1D',
639 '1R-imm': 'RM-1P-1S',
640 '1W-CRo': 'RM-1P-1D',
642 '1W-imm': 'RM-1P-1D',
643 '1W-CRi': 'RM-2P-1S1D',
644 'CRio': 'RM-2P-1S1D',
645 'CR=2R1W': 'RM-1P-2S1D',
649 'LDST-2R-imm': 'LDSTRM-2P-2S',
650 'LDST-2R-1W-imm': 'LDSTRM-2P-2S1D',
651 'LDST-2R-1W': 'LDSTRM-2P-2S1D',
652 'LDST-2R-2W': 'LDSTRM-2P-2S1D',
653 'LDST-1R-1W-imm': 'LDSTRM-2P-1S1D',
654 'LDST-1R-2W-imm': 'LDSTRM-2P-1S2D',
655 'LDST-3R': 'LDSTRM-2P-3S',
656 'LDST-3R-CRo': 'LDSTRM-2P-3S', # st*x
657 'LDST-3R-1W': 'LDSTRM-2P-2S1D', # st*x
659 print("# map to old SV Prefix")
661 print('|internal key | public name |')
662 print('|----- | ---------- |')
663 for key
in primarykeys
:
664 name
= keyname(dictkeys
[key
])
665 value
= mapsto
.get(name
, "-")
666 print(tformat([name
, value
+ " "]))
672 print(tformat(tablecols
) + " imms | name |")
673 print(tformat([" - "] * (len(tablecols
)+2)))
675 # print out the keys and the table from which they're derived
676 for key
in primarykeys
:
677 name
= keyname(dictkeys
[key
])
678 row
= tformat(dictkeys
[key
].values())
679 imms
= list(immediates
.get(key
, ""))
681 row
+= " %s | " % ("/".join(imms
))
682 row
+= " %s |" % name
687 # print out, by remap name, all the instructions under that category
688 for key
in primarykeys
:
689 name
= keyname(dictkeys
[key
])
690 value
= mapsto
.get(name
, "-")
691 print("## %s (%s)" % (name
, value
))
693 print(tformat(['CSV', 'opcode', 'asm', 'flags', 'form']))
694 print(tformat(['---', '------', '---', '-----', '----']))
702 # for fname, csv in csvs.items():
705 # for insn, row in insns.items():
708 print("# svp64 remaps")
709 svp64
= OrderedDict()
710 # create a CSV file, per category, with SV "augmentation" info
711 # XXX note: 'out2' not added here, needs to be added to CSV files
712 # KEEP TRACK OF THESE https://bugs.libre-soc.org/show_bug.cgi?id=619
713 csvcols
= ['insn', 'mode', 'CONDITIONS', 'Ptype', 'Etype',]
714 csvcols
+= ['0', '1', '2', '3']
715 csvcols
+= ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out'] # temporary
716 for key
in primarykeys
:
717 # get the decoded key containing row-analysis, and name/value
720 value
= mapsto
.get(name
, "-")
721 if value
== 'non-SV':
724 # print out svp64 tables by category
725 print("* **%s**: %s" % (name
, value
))
727 # store csv entries by svp64 RM category
728 if value
not in svp64
:
735 # for idx in range(len(row)):
736 # if row[idx] == 'NONE':
738 # get the instruction
742 insn
= insns
[(insn_name
, condition
)]
744 # start constructing svp64 CSV row
746 res
['insn'] = insn_name
747 res
['CONDITIONS'] = condition
748 res
['Ptype'] = value
.split('-')[1] # predication type (RM-xN-xxx)
749 # get whether R_xxx_EXTRAn fields are 2-bit or 3-bit
750 res
['Etype'] = 'EXTRA2'
751 # go through each register matching to Rxxxx_EXTRAx
752 for k
in ['0', '1', '2', '3']:
754 # create "fake" out2 (TODO, needs to be added to CSV files)
755 # KEEP TRACK HERE https://bugs.libre-soc.org/show_bug.cgi?id=619
757 if insn
['upd'] == '1': # LD/ST with update has RA as out2
760 # set the SVP64 mode to NORMAL, LDST, BRANCH or CR
761 crops
= ['mfcr', 'mfocrf', 'mtcrf', 'mtocrf',
764 if value
.startswith('LDST'):
765 if 'x' in insn_name
: # Indexed detection
769 elif insn_name
.startswith('bc'):
771 elif insn_name
.startswith('cr') or insn_name
in crops
:
775 # create a register profile list (update res row as well)
776 regs
= regs_profile(insn
, res
)
778 #print("regs", insn_name, regs)
779 extra_classifier(insn_name
, value
, name
, res
, regs
)
782 # for k in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
784 # if res['0'] != 'TODO':
786 if k
== 'CONDITIONS':
788 if res
[k
] == 'NONE' or res
[k
] == '':
790 svp64
[value
].append(res
)
791 # also add to by-CSV version
792 csv_fname
= insn_to_csv
[insn_name
]
793 csvs_svp64
[csv_fname
].append(res
)
797 # now write out the csv files
798 for value
, csv
in svp64
.items():
801 from time
import sleep
802 print ("WARNING, filename '-' should NOT exist. instrs missing")
803 print ("TODO: fix this (and put in the bugreport number here)")
805 # print out svp64 tables by category
806 print("## %s" % value
)
808 cols
= csvcols
+ ['out2']
810 print(tformat([" - "] * (len(cols
))))
818 #csvcols = ['insn', 'Ptype', 'Etype', '0', '1', '2', '3']
819 write_csv("%s.csv" % value
, csv
, csvcols
+ ['out2'])
821 # okaaay, now we re-read them back in for producing microwatt SV
823 # get SVP64 augmented CSV files
824 svt
= SVP64RM(microwatt_format
=True)
825 # Expand that (all .csv files)
826 pth
= find_wiki_file("*.csv")
828 # Ignore those containing: valid test sprs
829 for fname
in glob_valid_csvs(pth
):
830 svp64_csv
= svt
.get_svp64_csv(fname
)
832 csvcols
= ['insn', 'mode', 'Ptype', 'Etype']
833 csvcols
+= ['in1', 'in2', 'in3', 'out', 'out2', 'CR in', 'CR out']
835 if format
is Format
.VHDL
:
836 # and a nice microwatt VHDL file
837 file_path
= find_wiki_file("sv_decode.vhdl")
838 elif format
is Format
.BINUTILS
:
839 file_path
= find_wiki_file("binutils.c")
841 with
open(file_path
, 'w') as stream
:
842 output(format
, svt
, csvcols
, insns
, csvs_svp64
, stream
)
845 def output_autogen_disclaimer(format
, stream
):
847 "this file is auto-generated, do not edit",
848 "http://libre-soc.org/openpower/sv_analysis.py",
849 "part of Libre-SOC, sponsored by NLnet",
851 for line
in format
.wrap_comment(lines
):
857 def output(format
, svt
, csvcols
, insns
, csvs_svp64
, stream
):
871 def svp64_canonicalize(item
):
873 value
= value
.lower().replace("-", "_")
876 csvs_svp64_canon
= dict(map(svp64_canonicalize
, csvs_svp64
.items()))
879 output_autogen_disclaimer(format
, stream
)
882 for line
in format
.declarations(csvs_svp64_canon
.keys(), lens
):
883 stream
.write(f
"{line}\n")
886 sv_cols
= ['sv_in1', 'sv_in2', 'sv_in3', 'sv_out', 'sv_out2',
887 'sv_cr_in', 'sv_cr_out']
888 fullcols
= csvcols
+ sv_cols
890 entries_svp64
= defaultdict(list)
891 for (value
, csv
) in filter(lambda kv
: kv
[0] in lens
, csvs_svp64_canon
.items()):
893 insn
= str(entry
['insn'])
894 condition
= str(entry
['CONDITIONS'])
895 mode
= str(entry
['mode'])
896 sventry
= svt
.svp64_instrs
.get(insn
, None)
897 if sventry
is not None:
898 sventry
['mode'] = mode
899 op
= insns
[(insn
, condition
)]['opcode']
900 # binary-to-vhdl-binary
901 if op
.startswith("0b"):
902 op
= "2#%s#" % op
[2:]
904 for colname
in csvcols
[1:]:
906 # zero replace with NONE
910 re
= re
.replace("1P", "P1")
911 re
= re
.replace("2P", "P2")
913 #print("sventry", sventry)
914 for colname
in sv_cols
:
918 re
= sventry
[colname
]
920 entries_svp64
[value
].append((op
, insn
, row
))
922 for line
in format
.definitions(entries_svp64
, fullcols
):
923 stream
.write(f
"{line}\n")
928 os
.environ
['SILENCELOG'] = '1'
929 parser
= argparse
.ArgumentParser()
930 parser
.add_argument("-f", "--format",
931 type=Format
, choices
=Format
, default
=Format
.VHDL
,
932 help="format to be used (binutils or VHDL)")
933 args
= parser
.parse_args()
934 process_csvs(args
.format
)
937 if __name__
== '__main__':
938 # don't do anything other than call main() here, cuz this code is bypassed
939 # by the sv_analysis command created by setup.py