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']: # for now. TODO
319 if 'rfid' in insn_name
:
321 if 'addpcis' in insn_name
: # skip for now
324 # sv.bc is being classified as 2P-2S-1D by mistake due to SPRs
325 if insn_name
.startswith('bc'):
326 # whoops: remove out reg (SPRs CTR etc)
332 insns
[(insn_name
, condition
)] = row
# accumulate csv data
333 insn_to_csv
[insn_name
] = csvname_
# CSV file name by instruction
334 dkey
= create_key(row
)
335 key
= tuple(dkey
.values())
336 #print("key=", key, dkey)
341 bykey
[key
].append((csvname
, row
['opcode'], insn_name
, condition
,
342 row
['form'].upper() + '-Form'))
344 # detect immediates, collate them (useful info)
345 if row
['in2'].startswith('CONST_'):
346 imm
= row
['in2'].split("_")[1]
347 if key
not in immediates
:
348 immediates
[key
] = set()
349 immediates
[key
].add(imm
)
351 primarykeys
= list(primarykeys
)
354 return (csvs
, csvs_svp64
, primarykeys
, bykey
, insn_to_csv
, insns
,
355 dictkeys
, immediates
)
358 def regs_profile(insn
, res
):
359 """get a more detailed register profile: 1st operand is RA,
363 for k
in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
364 if insn
[k
].startswith('CONST'):
369 if insn
[k
] == 'RA_OR_ZERO':
371 elif insn
[k
] != 'NONE':
378 def extra_classifier(insn_name
, value
, name
, res
, regs
):
379 """extra_classifier: creates the SVP64.RM EXTRA2/3 classification.
380 there is very little space (9 bits) to mark register operands
381 (RT RA RB, BA BB, BFA, FRS etc.) with the "extra" information
382 needed to tell if *EACH* operand (of which there can be up to five!)
383 is Vectorised, and whether its numbering is extended into the
384 0..127 range rather than the limited 3/5 bit of Scalar v3.0 Power ISA.
386 thus begins the rather tedious but by-rote examination of EVERY
387 Scalar instruction, working out how best to tell a decoder how to
388 extend the registers. EXTRA2 can have up to 4 slots (of 2 bit each)
389 where due to RM.EXTRA being 9 bits, EXTRA3 can have up to 3 slots
390 (of 3 bit each). the index REGNAME says which slot the register
391 named REGNAME must read its decoding from. d: means destination,
392 s: means source. some are *shared slots* especially LDST update.
393 some Rc=1 ops have the CR0/CR1 as a co-result which is also
394 obviously Vectorised if the result is Vectorised.
396 it is actually quite straightforward but the sheer quantity of
397 Scalar Power ISA instructions made it prudent to do this in an
398 intelligent way, almost by-rote, by analysing the register profiles.
400 # for LD/ST FP, use FRT/FRS not RT/RS, and use CR1 not CR0
401 if insn_name
.startswith("lf"):
407 if insn_name
.startswith("stf"):
414 # sigh now the fun begins. this isn't the sanest way to do it
415 # but the patterns are pretty regular. we start with the "profile"
416 # because that determines how much space is available (total num
417 # regs to decode) then if necessary begin apecialising either
418 # by the instruction name or through more detailed register
419 # profiling. example:
420 # if regs == ['RA', '', '', 'RT', '', '']:
421 # is in the order in1 in2 in3 out1 out2 Rc=1
426 if value
== 'LDSTRM-2P-1S1D':
427 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
428 res
['0'] = dRT
# RT: Rdest_EXTRA3
429 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
431 elif value
== 'LDSTRM-2P-1S2D':
432 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
433 res
['0'] = dRT
# RT: Rdest_EXTRA3
434 res
['1'] = 'd:RA' # RA: Rdest2_EXTRA2
435 res
['2'] = 's:RA' # RA: Rsrc1_EXTRA2
437 elif value
== 'LDSTRM-2P-2S':
439 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
440 res
['0'] = sRS
# RS: Rdest1_EXTRA3
441 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
443 elif value
== 'LDSTRM-2P-2S1D':
444 if 'st' in insn_name
and 'x' not in insn_name
: # stwu/stbu etc
445 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
446 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA2
447 res
['1'] = sRS
# RS: Rdsrc1_EXTRA2
448 res
['2'] = 's:RA' # RA: Rsrc2_EXTRA2
449 elif 'st' in insn_name
and 'x' in insn_name
: # stwux
450 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
451 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA2
452 # RS: Rdest2_EXTRA2, RA: Rsrc1_EXTRA2
453 res
['1'] = "%s;%s" % (sRS
, 's:RA')
454 res
['2'] = 's:RB' # RB: Rsrc2_EXTRA2
455 elif 'u' in insn_name
: # ldux etc.
456 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
457 res
['0'] = dRT
# RT: Rdest1_EXTRA2
458 res
['1'] = 'd:RA' # RA: Rdest2_EXTRA2
459 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA2
461 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
462 res
['0'] = dRT
# RT: Rdest1_EXTRA2
463 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
464 res
['2'] = 's:RB' # RB: Rsrc2_EXTRA2
466 elif value
== 'LDSTRM-2P-3S':
467 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
468 if 'cx' in insn_name
:
469 res
['0'] = "%s;%s" % (sRS
, dCR
) # RS: Rsrc1_EXTRA2 CR0: dest
471 res
['0'] = sRS
# RS: Rsrc1_EXTRA2
472 res
['1'] = 's:RA' # RA: Rsrc2_EXTRA2
473 res
['2'] = 's:RB' # RA: Rsrc3_EXTRA2
476 # now begins,arithmetic
478 elif value
== 'RM-2P-1S1D':
479 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
480 if insn_name
== 'mtspr':
481 res
['0'] = 'd:SPR' # SPR: Rdest1_EXTRA3
482 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
483 elif insn_name
== 'mfspr':
484 res
['0'] = 'd:RS' # RS: Rdest1_EXTRA3
485 res
['1'] = 's:SPR' # SPR: Rsrc1_EXTRA3
486 elif name
== 'CRio' and insn_name
== 'mcrf':
487 res
['0'] = 'd:BF' # BFA: Rdest1_EXTRA3
488 res
['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
489 elif 'mfcr' in insn_name
or 'mfocrf' in insn_name
:
490 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
491 res
['1'] = 's:CR' # CR: Rsrc1_EXTRA3
492 elif insn_name
== 'setb':
493 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
494 res
['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
495 elif insn_name
.startswith('cmp'): # cmpi
496 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
497 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
498 elif regs
== ['RA', '', '', 'RT', '', '']:
499 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
500 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
501 elif regs
== ['RA', '', '', 'RT', '', 'CR0']:
502 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
503 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
504 elif (regs
== ['RS', '', '', 'RA', '', 'CR0'] or
505 regs
== ['', '', 'RS', 'RA', '', 'CR0']):
506 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
507 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
508 elif regs
== ['RS', '', '', 'RA', '', '']:
509 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA3
510 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
511 elif regs
== ['', 'FRB', '', 'FRT', '0', 'CR1']:
512 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
513 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
514 elif regs
== ['', 'FRB', '', '', '', 'CR1']:
515 res
['0'] = 'd:CR1' # CR1: Rdest1_EXTRA3
516 res
['1'] = 's:FRB' # FRA: Rsrc1_EXTRA3
517 elif regs
== ['', 'FRB', '', '', '', 'BF']:
518 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
519 res
['1'] = 's:FRB' # FRA: Rsrc1_EXTRA3
520 elif regs
== ['', 'FRB', '', 'FRT', '', 'CR1']:
521 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
522 res
['1'] = 's:FRB' # FRB: Rsrc1_EXTRA3
523 elif insn_name
== 'fishmv':
524 # an overwrite instruction
525 res
['0'] = 'd:FRS' # FRS: Rdest1_EXTRA3
526 res
['1'] = 's:FRS' # FRS: Rsrc1_EXTRA3
527 elif insn_name
== 'setvl':
528 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
529 res
['1'] = 's:RA' # RS: Rsrc1_EXTRA3
532 print("regs TODO", insn_name
, regs
)
534 elif value
== 'RM-1P-2S1D':
535 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
536 if insn_name
.startswith('cr'):
537 res
['0'] = 'd:BT' # BT: Rdest1_EXTRA3
538 res
['1'] = 's:BA' # BA: Rsrc1_EXTRA3
539 res
['2'] = 's:BB' # BB: Rsrc2_EXTRA3
540 elif regs
== ['FRA', '', 'FRC', 'FRT', '', 'CR1']:
541 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
542 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
543 res
['2'] = 's:FRC' # FRC: Rsrc1_EXTRA3
545 elif regs
== ['FRA', 'FRB', '', '', '', 'BF']:
546 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
547 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
548 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
549 elif regs
== ['FRA', 'FRB', '', 'FRT', '', '']:
550 res
['0'] = 'd:FRT' # FRT: Rdest1_EXTRA3
551 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
552 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
553 elif regs
== ['FRA', 'FRB', '', 'FRT', '', 'CR1']:
554 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
555 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
556 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
557 elif regs
== ['FRA', 'RB', '', 'FRT', '', 'CR1']:
558 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
559 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
560 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
561 elif name
== '2R-1W' or insn_name
== 'cmpb': # cmpb
562 if insn_name
in ['bpermd', 'cmpb']:
563 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA3
564 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
566 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
567 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
568 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
569 elif insn_name
.startswith('cmp'): # cmp
570 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
571 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
572 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
573 elif (regs
== ['', 'RB', 'RS', 'RA', '', 'CR0'] or
574 regs
== ['RS', 'RB', '', 'RA', '', 'CR0']):
575 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
576 res
['1'] = 's:RB' # RB: Rsrc1_EXTRA3
577 res
['2'] = 's:RS' # RS: Rsrc1_EXTRA3
578 elif regs
== ['RA', 'RB', '', 'RT', '', 'CR0']:
579 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
580 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
581 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
582 elif regs
== ['RA', '', 'RS', 'RA', '', 'CR0']:
583 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
584 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
585 res
['2'] = 's:RS' # RS: Rsrc1_EXTRA3
589 elif value
== 'RM-2P-2S1D':
590 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
591 if insn_name
.startswith('mt'): # mtcrf
592 res
['0'] = 'd:CR' # CR: Rdest1_EXTRA2
593 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA2
594 res
['2'] = 's:CR' # CR: Rsrc2_EXTRA2
598 elif value
== 'RM-1P-3S1D':
599 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
600 if regs
== ['FRT', 'FRB', 'FRA', 'FRT', '', 'CR1']: # ffmadds/fdmadds
601 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA2
602 res
['1'] = 's:FRT' # FRT: Rsrc1_EXTRA2
603 res
['2'] = 's:FRB' # FRB: Rsrc2_EXTRA2
604 res
['3'] = 's:FRA' # FRA: Rsrc3_EXTRA2
605 elif regs
== ['RA', 'RB', 'RC', 'RT', '', '']: # madd*
606 res
['0'] = 'd:RT' # RT,CR0: Rdest1_EXTRA2
607 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
608 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
609 res
['3'] = 's:RC' # RT: Rsrc3_EXTRA2
610 elif regs
== ['RA', 'RB', 'RC', 'RT', '', 'CR0']: # pcdec
611 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA2
612 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
613 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
614 res
['3'] = 's:RC' # RT: Rsrc3_EXTRA2
615 elif regs
== ['RA', 'RB', 'RT', 'RT', '', 'CR0']: # overwrite 3-in
616 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA2
617 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
618 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
619 res
['3'] = 's:RT' # RT: Rsrc3_EXTRA2
620 elif insn_name
== 'isel':
621 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA2
622 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
623 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
624 res
['3'] = 's:BC' # BC: Rsrc3_EXTRA2
626 res
['0'] = 'd:FRT;d:CR1' # FRT, CR1: Rdest1_EXTRA2
627 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA2
628 res
['2'] = 's:FRB' # FRB: Rsrc2_EXTRA2
629 res
['3'] = 's:FRC' # FRC: Rsrc3_EXTRA2
631 elif value
== 'RM-1P-1D':
632 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
633 if insn_name
== 'svstep':
634 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
635 if insn_name
== 'fmvis':
636 res
['0'] = 'd:FRS' # FRS: Rdest1_EXTRA3
638 # HACK! thos should be RM-1P-1S butvthere is a bug with sv.bc
639 elif value
== 'RM-2P-1S':
640 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
641 if insn_name
.startswith('bc'):
642 res
['0'] = 's:BI' # BI: Rsrc1_EXTRA3
645 def process_csvs(format
):
647 print("# Draft SVP64 Power ISA register 'profile's")
649 print("this page is auto-generated, do not edit")
650 print("created by http://libre-soc.org/openpower/sv_analysis.py")
653 (csvs
, csvs_svp64
, primarykeys
, bykey
, insn_to_csv
, insns
,
654 dictkeys
, immediates
) = read_csvs()
656 # mapping to old SVPrefix "Forms"
657 mapsto
= {'3R-1W-CRo': 'RM-1P-3S1D',
658 '3R-1W': 'RM-1P-3S1D',
659 '2R-1W-CRio': 'RM-1P-2S1D',
660 '2R-1W-CRi': 'RM-1P-3S1D',
661 '2R-1W-CRo': 'RM-1P-2S1D',
663 '2R-1W': 'RM-1P-2S1D',
664 '1R-CRio': 'RM-2P-2S1D',
665 '2R-CRio': 'RM-1P-2S1D',
666 '2R-CRo': 'RM-1P-2S1D',
668 '1R-1W-CRio': 'RM-2P-1S1D',
669 '1R-1W-CRo': 'RM-2P-1S1D',
670 '1R-1W': 'RM-2P-1S1D',
671 '1R-1W-imm': 'RM-2P-1S1D',
672 '1R-CRo': 'RM-2P-1S1D',
673 '1R-imm': 'RM-1P-1S',
674 '1W-CRo': 'RM-1P-1D',
676 '1W-imm': 'RM-1P-1D',
677 '1W-CRi': 'RM-2P-1S1D',
678 'CRio': 'RM-2P-1S1D',
679 'CR=2R1W': 'RM-1P-2S1D',
680 'CRi': 'RM-2P-1S', # HACK, bc here, it should be 1P
683 'LDST-2R-imm': 'LDSTRM-2P-2S',
684 'LDST-2R-1W-imm': 'LDSTRM-2P-2S1D',
685 'LDST-2R-1W': 'LDSTRM-2P-2S1D',
686 'LDST-2R-2W': 'LDSTRM-2P-2S1D',
687 'LDST-1R-1W-imm': 'LDSTRM-2P-1S1D',
688 'LDST-1R-2W-imm': 'LDSTRM-2P-1S2D',
689 'LDST-3R': 'LDSTRM-2P-3S',
690 'LDST-3R-CRo': 'LDSTRM-2P-3S', # st*x
691 'LDST-3R-1W': 'LDSTRM-2P-2S1D', # st*x
693 print("# map to old SV Prefix")
695 print('|internal key | public name |')
696 print('|----- | ---------- |')
697 for key
in primarykeys
:
698 name
= keyname(dictkeys
[key
])
699 value
= mapsto
.get(name
, "-")
700 print(tformat([name
, value
+ " "]))
706 print(tformat(tablecols
) + " imms | name |")
707 print(tformat([" - "] * (len(tablecols
)+2)))
709 # print out the keys and the table from which they're derived
710 for key
in primarykeys
:
711 name
= keyname(dictkeys
[key
])
712 row
= tformat(dictkeys
[key
].values())
713 imms
= list(immediates
.get(key
, ""))
715 row
+= " %s | " % ("/".join(imms
))
716 row
+= " %s |" % name
721 # print out, by remap name, all the instructions under that category
722 for key
in primarykeys
:
723 name
= keyname(dictkeys
[key
])
724 value
= mapsto
.get(name
, "-")
725 print("## %s (%s)" % (name
, value
))
727 print(tformat(['CSV', 'opcode', 'asm', 'flags', 'form']))
728 print(tformat(['---', '------', '---', '-----', '----']))
736 # for fname, csv in csvs.items():
739 # for insn, row in insns.items():
742 print("# svp64 remaps")
743 svp64
= OrderedDict()
744 # create a CSV file, per category, with SV "augmentation" info
745 # XXX note: 'out2' not added here, needs to be added to CSV files
746 # KEEP TRACK OF THESE https://bugs.libre-soc.org/show_bug.cgi?id=619
747 csvcols
= ['insn', 'mode', 'CONDITIONS', 'Ptype', 'Etype', 'SM']
748 csvcols
+= ['0', '1', '2', '3']
749 csvcols
+= ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out'] # temporary
750 for key
in primarykeys
:
751 # get the decoded key containing row-analysis, and name/value
754 value
= mapsto
.get(name
, "-")
755 if value
== 'non-SV':
758 # print out svp64 tables by category
759 print("* **%s**: %s" % (name
, value
))
761 # store csv entries by svp64 RM category
762 if value
not in svp64
:
769 # for idx in range(len(row)):
770 # if row[idx] == 'NONE':
772 # get the instruction
776 insn
= insns
[(insn_name
, condition
)]
778 # start constructing svp64 CSV row
780 res
['insn'] = insn_name
781 res
['CONDITIONS'] = condition
782 res
['Ptype'] = value
.split('-')[1] # predication type (RM-xN-xxx)
783 # get whether R_xxx_EXTRAn fields are 2-bit or 3-bit
784 res
['Etype'] = 'EXTRA2'
785 # go through each register matching to Rxxxx_EXTRAx
786 for k
in ['0', '1', '2', '3']:
788 # create "fake" out2 (TODO, needs to be added to CSV files)
789 # KEEP TRACK HERE https://bugs.libre-soc.org/show_bug.cgi?id=619
791 if insn
['upd'] == '1': # LD/ST with update has RA as out2
794 # set the SVP64 mode to NORMAL, LDST, BRANCH or CR
795 crops
= ['mfcr', 'mfocrf', 'mtcrf', 'mtocrf',
798 if value
.startswith('LDST'):
799 if 'x' in insn_name
: # Indexed detection
803 elif insn_name
.startswith('bc'):
805 elif insn_name
.startswith('cmp') or insn_name
.startswith('cr') or insn_name
in crops
:
809 # create a register profile list (update res row as well)
810 regs
= regs_profile(insn
, res
)
812 #print("regs", insn_name, regs)
813 extra_classifier(insn_name
, value
, name
, res
, regs
)
815 # source-mask is hard to detect, it's part of RM-nn-nn.
816 # to make style easier, create a yes/no decision here
817 # see https://libre-soc.org/openpower/sv/svp64/#extra_remap
819 vstripped
= value
.replace("LDST", "")
820 if vstripped
in ['RM-2P-1S1D', 'RM-2P-2S',
821 'RM-2P-2S1D', 'RM-2P-1S2D', 'RM-2P-3S',
827 # for k in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
829 # if res['0'] != 'TODO':
831 if k
== 'CONDITIONS':
833 if res
[k
] == 'NONE' or res
[k
] == '':
835 svp64
[value
].append(res
)
836 # also add to by-CSV version
837 csv_fname
= insn_to_csv
[insn_name
]
838 csvs_svp64
[csv_fname
].append(res
)
842 # now write out the csv files
843 for value
, csv
in svp64
.items():
846 from time
import sleep
847 print("WARNING, filename '-' should NOT exist. instrs missing")
848 print("TODO: fix this (and put in the bugreport number here)")
850 # print out svp64 tables by category
851 print("## %s" % value
)
853 cols
= csvcols
+ ['out2']
855 print(tformat([" - "] * (len(cols
))))
863 #csvcols = ['insn', 'Ptype', 'Etype', '0', '1', '2', '3']
864 write_csv("%s.csv" % value
, csv
, csvcols
+ ['out2'])
866 # okaaay, now we re-read them back in for producing microwatt SV
868 # get SVP64 augmented CSV files
869 svt
= SVP64RM(microwatt_format
=True)
870 # Expand that (all .csv files)
871 pth
= find_wiki_file("*.csv")
873 # Ignore those containing: valid test sprs
874 for fname
in glob_valid_csvs(pth
):
875 svp64_csv
= svt
.get_svp64_csv(fname
)
877 csvcols
= ['insn', 'mode', 'Ptype', 'Etype', 'SM']
878 csvcols
+= ['in1', 'in2', 'in3', 'out', 'out2', 'CR in', 'CR out']
880 if format
is Format
.VHDL
:
881 # and a nice microwatt VHDL file
882 file_path
= find_wiki_file("sv_decode.vhdl")
883 elif format
is Format
.BINUTILS
:
884 file_path
= find_wiki_file("binutils.c")
886 with
open(file_path
, 'w') as stream
:
887 output(format
, svt
, csvcols
, insns
, csvs_svp64
, stream
)
890 def output_autogen_disclaimer(format
, stream
):
892 "this file is auto-generated, do not edit",
893 "http://libre-soc.org/openpower/sv_analysis.py",
894 "part of Libre-SOC, sponsored by NLnet",
896 for line
in format
.wrap_comment(lines
):
902 def output(format
, svt
, csvcols
, insns
, csvs_svp64
, stream
):
916 def svp64_canonicalize(item
):
918 value
= value
.lower().replace("-", "_")
921 csvs_svp64_canon
= dict(map(svp64_canonicalize
, csvs_svp64
.items()))
924 output_autogen_disclaimer(format
, stream
)
927 for line
in format
.declarations(csvs_svp64_canon
.keys(), lens
):
928 stream
.write(f
"{line}\n")
931 sv_cols
= ['sv_in1', 'sv_in2', 'sv_in3', 'sv_out', 'sv_out2',
932 'sv_cr_in', 'sv_cr_out']
933 fullcols
= csvcols
+ sv_cols
935 entries_svp64
= defaultdict(list)
936 for (value
, csv
) in filter(lambda kv
: kv
[0] in lens
, csvs_svp64_canon
.items()):
938 insn
= str(entry
['insn'])
939 condition
= str(entry
['CONDITIONS'])
940 mode
= str(entry
['mode'])
941 sventry
= svt
.svp64_instrs
.get(insn
, None)
942 if sventry
is not None:
943 sventry
['mode'] = mode
944 op
= insns
[(insn
, condition
)]['opcode']
945 # binary-to-vhdl-binary
946 if op
.startswith("0b"):
947 op
= "2#%s#" % op
[2:]
949 for colname
in csvcols
[1:]:
951 # zero replace with NONE
955 re
= re
.replace("1P", "P1")
956 re
= re
.replace("2P", "P2")
958 #print("sventry", sventry)
959 for colname
in sv_cols
:
963 re
= sventry
[colname
]
965 entries_svp64
[value
].append((op
, insn
, row
))
967 for line
in format
.definitions(entries_svp64
, fullcols
):
968 stream
.write(f
"{line}\n")
973 os
.environ
['SILENCELOG'] = '1'
974 parser
= argparse
.ArgumentParser()
975 parser
.add_argument("-f", "--format",
976 type=Format
, choices
=Format
, default
=Format
.VHDL
,
977 help="format to be used (binutils or VHDL)")
978 args
= parser
.parse_args()
979 process_csvs(args
.format
)
982 if __name__
== '__main__':
983 # don't do anything other than call main() here, cuz this code is bypassed
984 # by the sv_analysis command created by setup.py