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 # Write an array of dictionaries to the CSV file name:
37 def write_csv(name
, items
, headers
):
38 file_path
= find_wiki_file(name
)
39 with
open(file_path
, 'w') as csvfile
:
40 writer
= csv
.DictWriter(csvfile
, headers
, lineterminator
="\n")
42 writer
.writerows(items
)
44 # This will return True if all values are true.
45 # Not sure what this is about
49 # for v in row.values():
50 # if 'SPR' in v: # skip all SPRs
52 for v
in row
.values():
57 # General purpose registers have names like: RA, RT, R1, ...
58 # Floating point registers names like: FRT, FRA, FR1, ..., FRTp, ...
59 # Return True if field is a register
63 return (field
.startswith('R') or field
.startswith('FR') or
67 # These are the attributes of the instructions,
69 keycolumns
= ['unit', 'in1', 'in2', 'in3', 'out', 'CR in', 'CR out',
70 ] # don't think we need these: 'ldst len', 'rc', 'lk']
72 tablecols
= ['unit', 'in', 'outcnt', 'CR in', 'CR out', 'imm'
73 ] # don't think we need these: 'ldst len', 'rc', 'lk']
77 """ create an equivalent of a database key by which it is possible
78 to easily categorise an instruction. later this category is used
79 to decide what kind of EXTRA encoding is to be done because the
80 key contains the total number of input and output registers
84 for key
in keycolumns
:
85 # registers IN - special-case: count number of regs RA/RB/RC/RS
86 if key
in ['in1', 'in2', 'in3']:
89 if row
['unit'] == 'BRANCH': # branches must not include Vector SPRs
96 # If upd is 1 then increment the count of outputs
97 if 'outcnt' not in res
:
101 if row
['upd'] == '1':
104 # CRs (Condition Register) (CR0 .. CR7)
105 if key
.startswith('CR'):
106 if row
[key
].startswith('NONE'):
110 if row
['comment'].startswith('cr'):
114 if row
[key
] == 'LDST': # we care about LDST units
118 # LDST len (LoadStore length)
119 if key
.startswith('ldst'):
120 if row
[key
].startswith('NONE'):
125 if key
in ['rc', 'lk']:
126 if row
[key
] == 'ONE':
128 elif row
[key
] == 'NONE':
135 # Convert the numerics 'in' & 'outcnt' to strings
136 res
['in'] = str(res
['in'])
137 res
['outcnt'] = str(res
['outcnt'])
140 if row
['in2'].startswith('CONST_'):
141 res
['imm'] = "1" # row['in2'].split("_")[1]
152 for k
, v
in d
.items():
153 res
.append("%s: %s" % (k
, v
))
158 return "| " + ' | '.join(d
) + " |"
162 """converts a key into a readable string. anything null or zero
163 is skipped, shortening the readable string
166 if row
['unit'] != 'OTHER':
167 res
.append(row
['unit'])
169 res
.append('%sR' % row
['in'])
170 if row
['outcnt'] != '0':
171 res
.append('%sW' % row
['outcnt'])
172 if row
['CR in'] == '1' and row
['CR out'] == '1':
174 res
.append("CR=2R1W")
177 elif row
['CR in'] == '1':
179 elif row
['CR out'] == '1':
181 elif 'imm' in row
and row
['imm']:
186 class Format(enum
.Enum
):
187 BINUTILS
= enum
.auto()
191 def _missing_(cls
, value
):
193 "binutils": Format
.BINUTILS
,
198 return self
.name
.lower()
200 def declarations(self
, values
, lens
):
201 def declaration_binutils(value
, width
):
202 yield f
"/* TODO: implement binutils declaration (value={value!r}, width={width!r}) */"
204 def declaration_vhdl(value
, width
):
205 yield f
" type sv_{value}_rom_array_t is " \
206 f
"array(0 to {width}) of sv_decode_rom_t;"
209 if value
not in lens
:
210 todo
= [f
"TODO {value} (or no SVP64 augmentation)"]
211 todo
= self
.wrap_comment(todo
)
212 yield from map(lambda line
: f
" {line}", todo
)
216 Format
.BINUTILS
: declaration_binutils
,
217 Format
.VHDL
: declaration_vhdl
,
218 }[self
](value
, width
)
220 def definitions(self
, entries_svp64
, fullcols
):
221 def definitions_vhdl():
222 for (value
, entries
) in entries_svp64
.items():
224 yield f
" constant sv_{value}_decode_rom_array :"
225 yield f
" sv_{value}_rom_array_t := ("
226 yield f
" -- {' '.join(fullcols)}"
228 for (op
, insn
, row
) in entries
:
229 yield f
" {op:>13} => ({', '.join(row)}), -- {insn}"
231 yield f
" {'others':>13} => sv_illegal_inst"
235 def definitions_binutils():
236 yield f
"/* TODO: implement binutils definitions */"
239 Format
.BINUTILS
: definitions_binutils
,
240 Format
.VHDL
: definitions_vhdl
,
243 def wrap_comment(self
, lines
):
244 def wrap_comment_binutils(lines
):
247 yield f
"/* {lines[0]} */"
250 yield from map(lambda line
: f
" * {line}", lines
)
253 def wrap_comment_vhdl(lines
):
254 yield from map(lambda line
: f
"-- {line}", lines
)
257 Format
.BINUTILS
: wrap_comment_binutils
,
258 Format
.VHDL
: wrap_comment_vhdl
,
267 dictkeys
= OrderedDict()
269 insns
= {} # dictionary of CSV row, by instruction
272 # Expand that (all .csv files)
273 pth
= find_wiki_file("*.csv")
275 # Ignore those containing: valid test sprs
276 for fname
in glob(pth
):
277 #print("sv analysis checking", fname)
278 _
, name
= os
.path
.split(fname
)
285 if fname
.endswith('sprs.csv'):
287 if fname
.endswith('minor_19_valid.csv'):
291 csvname
= os
.path
.split(fname
)[1]
292 csvname_
= csvname
.split(".")[0]
293 # csvname is something like: minor_59.csv, fname the whole path
296 csvs_svp64
[csvname_
] = []
301 insn_name
= row
['comment']
302 condition
= row
['CONDITIONS']
303 # skip instructions that are not suitable
304 if insn_name
.startswith("l") and insn_name
.endswith("br"):
305 continue # skip pseudo-alias lxxxbr
306 if insn_name
in ['mcrxr', 'mcrxrx', 'darn']:
308 if insn_name
in ['bctar', 'bcctr']:
310 if 'rfid' in insn_name
:
312 if insn_name
in ['setvl', ]: # SVP64 opcodes
315 insns
[(insn_name
, condition
)] = row
# accumulate csv data
316 insn_to_csv
[insn_name
] = csvname_
# CSV file name by instruction
317 dkey
= create_key(row
)
318 key
= tuple(dkey
.values())
319 #print("key=", key, dkey)
324 bykey
[key
].append((csvname
, row
['opcode'], insn_name
, condition
,
325 row
['form'].upper() + '-Form'))
327 # detect immediates, collate them (useful info)
328 if row
['in2'].startswith('CONST_'):
329 imm
= row
['in2'].split("_")[1]
330 if key
not in immediates
:
331 immediates
[key
] = set()
332 immediates
[key
].add(imm
)
334 primarykeys
= list(primarykeys
)
337 return (csvs
, csvs_svp64
, primarykeys
, bykey
, insn_to_csv
, insns
,
338 dictkeys
, immediates
)
341 def regs_profile(insn
, res
):
342 """get a more detailed register profile: 1st operand is RA,
346 for k
in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
347 if insn
[k
].startswith('CONST'):
352 if insn
[k
] == 'RA_OR_ZERO':
354 elif insn
[k
] != 'NONE':
361 def extra_classifier(insn_name
, value
, name
, res
, regs
):
362 """extra_classifier: creates the SVP64.RM EXTRA2/3 classification.
363 there is very little space (9 bits) to mark register operands
364 (RT RA RB, BA BB, BFA, FRS etc.) with the "extra" information
365 needed to tell if *EACH* operand (of which there can be up to five!)
366 is Vectorised, and whether its numbering is extended into the
367 0..127 range rather than the limited 3/5 bit of Scalar v3.0 Power ISA.
369 thus begins the rather tedious but by-rote examination of EVERY
370 Scalar instruction, working out how best to tell a decoder how to
371 extend the registers. EXTRA2 can have up to 4 slots (of 2 bit each)
372 where due to RM.EXTRA being 9 bits, EXTRA3 can have up to 3 slots
373 (of 3 bit each). the index REGNAME says which slot the register
374 named REGNAME must read its decoding from. d: means destination,
375 s: means source. some are *shared slots* especially LDST update.
376 some Rc=1 ops have the CR0/CR1 as a co-result which is also
377 obviously Vectorised if the result is Vectorised.
379 it is actually quite straightforward but the sheer quantity of
380 Scalar Power ISA instructions made it prudent to do this in an
381 intelligent way, almost by-rote, by analysing the register profiles.
383 # for LD/ST FP, use FRT/FRS not RT/RS, and use CR1 not CR0
384 if insn_name
.startswith("lf"):
390 if insn_name
.startswith("stf"):
397 # sigh now the fun begins. this isn't the sanest way to do it
398 # but the patterns are pretty regular. we start with the "profile"
399 # because that determines how much space is available (total num
400 # regs to decode) then if necessary begin apecialising either
401 # by the instruction name or through more detailed register
402 # profiling. example:
403 # if regs == ['RA', '', '', 'RT', '', '']:
404 # is in the order in1 in2 in3 out1 out2 Rc=1
409 if value
== 'LDSTRM-2P-1S1D':
410 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
411 res
['0'] = dRT
# RT: Rdest_EXTRA3
412 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
414 elif value
== 'LDSTRM-2P-1S2D':
415 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
416 res
['0'] = dRT
# RT: Rdest_EXTRA3
417 res
['1'] = 'd:RA' # RA: Rdest2_EXTRA2
418 res
['2'] = 's:RA' # RA: Rsrc1_EXTRA2
420 elif value
== 'LDSTRM-2P-2S':
422 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
423 res
['0'] = sRS
# RS: Rdest1_EXTRA3
424 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
426 elif value
== 'LDSTRM-2P-2S1D':
427 if 'st' in insn_name
and 'x' not in insn_name
: # stwu/stbu etc
428 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
429 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA2
430 res
['1'] = sRS
# RS: Rdsrc1_EXTRA2
431 res
['2'] = 's:RA' # RA: Rsrc2_EXTRA2
432 elif 'st' in insn_name
and 'x' in insn_name
: # stwux
433 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
434 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA2
435 # RS: Rdest2_EXTRA2, RA: Rsrc1_EXTRA2
436 res
['1'] = "%s;%s" % (sRS
, 's:RA')
437 res
['2'] = 's:RB' # RB: Rsrc2_EXTRA2
438 elif 'u' in insn_name
: # ldux etc.
439 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
440 res
['0'] = dRT
# RT: Rdest1_EXTRA2
441 res
['1'] = 'd:RA' # RA: Rdest2_EXTRA2
442 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA2
444 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
445 res
['0'] = dRT
# RT: Rdest1_EXTRA2
446 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
447 res
['2'] = 's:RB' # RB: Rsrc2_EXTRA2
449 elif value
== 'LDSTRM-2P-3S':
450 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
451 if 'cx' in insn_name
:
452 res
['0'] = "%s;%s" % (sRS
, dCR
) # RS: Rsrc1_EXTRA2 CR0: dest
454 res
['0'] = sRS
# RS: Rsrc1_EXTRA2
455 res
['1'] = 's:RA' # RA: Rsrc2_EXTRA2
456 res
['2'] = 's:RB' # RA: Rsrc3_EXTRA2
459 # now begins,arithmetic
461 elif value
== 'RM-2P-1S1D':
462 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
463 if insn_name
== 'mtspr':
464 res
['0'] = 'd:SPR' # SPR: Rdest1_EXTRA3
465 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
466 elif insn_name
== 'mfspr':
467 res
['0'] = 'd:RS' # RS: Rdest1_EXTRA3
468 res
['1'] = 's:SPR' # SPR: Rsrc1_EXTRA3
469 elif name
== 'CRio' and insn_name
== 'mcrf':
470 res
['0'] = 'd:BF' # BFA: Rdest1_EXTRA3
471 res
['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
472 elif 'mfcr' in insn_name
or 'mfocrf' in insn_name
:
473 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
474 res
['1'] = 's:CR' # CR: Rsrc1_EXTRA3
475 elif insn_name
== 'setb':
476 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
477 res
['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
478 elif insn_name
.startswith('cmp'): # cmpi
479 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
480 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
481 elif regs
== ['RA', '', '', 'RT', '', '']:
482 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
483 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
484 elif regs
== ['RA', '', '', 'RT', '', 'CR0']:
485 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
486 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
487 elif (regs
== ['RS', '', '', 'RA', '', 'CR0'] or
488 regs
== ['', '', 'RS', 'RA', '', 'CR0']):
489 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
490 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
491 elif regs
== ['RS', '', '', 'RA', '', '']:
492 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA3
493 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
494 elif regs
== ['', 'FRB', '', 'FRT', '0', 'CR1']:
495 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
496 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
497 elif regs
== ['', 'FRB', '', '', '', 'CR1']:
498 res
['0'] = 'd:CR1' # CR1: Rdest1_EXTRA3
499 res
['1'] = 's:FRB' # FRA: Rsrc1_EXTRA3
500 elif regs
== ['', 'FRB', '', '', '', 'BF']:
501 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
502 res
['1'] = 's:FRB' # FRA: Rsrc1_EXTRA3
503 elif regs
== ['', 'FRB', '', 'FRT', '', 'CR1']:
504 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
505 res
['1'] = 's:FRB' # FRB: Rsrc1_EXTRA3
506 elif insn_name
.startswith('bc'):
507 res
['0'] = 'd:BI' # BI: Rdest1_EXTRA3
508 res
['1'] = 's:BI' # BI: Rsrc1_EXTRA3
509 elif insn_name
== 'fishmv':
510 # an overwrite ibstruction
511 res
['0'] = 'd:FRS' # FRS: Rdest1_EXTRA3
512 res
['1'] = 's:FRS' # FRS: Rsrc1_EXTRA3
515 print("regs TODO", insn_name
, regs
)
517 elif value
== 'RM-1P-2S1D':
518 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
519 if insn_name
.startswith('cr'):
520 res
['0'] = 'd:BT' # BT: Rdest1_EXTRA3
521 res
['1'] = 's:BA' # BA: Rsrc1_EXTRA3
522 res
['2'] = 's:BB' # BB: Rsrc2_EXTRA3
523 elif regs
== ['FRA', '', 'FRC', 'FRT', '', 'CR1']:
524 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
525 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
526 res
['2'] = 's:FRC' # FRC: Rsrc1_EXTRA3
528 elif regs
== ['FRA', 'FRB', '', '', '', 'BF']:
529 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
530 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
531 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
532 elif regs
== ['FRA', 'FRB', '', 'FRT', '', '']:
533 res
['0'] = 'd:FRT' # FRT: Rdest1_EXTRA3
534 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
535 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
536 elif regs
== ['FRA', 'FRB', '', 'FRT', '', 'CR1']:
537 res
['0'] = 'd:FRT;d:CR1' # FRT,CR1: Rdest1_EXTRA3
538 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA3
539 res
['2'] = 's:FRB' # FRB: Rsrc1_EXTRA3
540 elif name
== '2R-1W' or insn_name
== 'cmpb': # cmpb
541 if insn_name
in ['bpermd', 'cmpb']:
542 res
['0'] = 'd:RA' # RA: Rdest1_EXTRA3
543 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA3
545 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA3
546 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
547 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
548 elif insn_name
.startswith('cmp'): # cmp
549 res
['0'] = 'd:BF' # BF: Rdest1_EXTRA3
550 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
551 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
552 elif (regs
== ['', 'RB', 'RS', 'RA', '', 'CR0'] or
553 regs
== ['RS', 'RB', '', 'RA', '', 'CR0']):
554 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
555 res
['1'] = 's:RB' # RB: Rsrc1_EXTRA3
556 res
['2'] = 's:RS' # RS: Rsrc1_EXTRA3
557 elif regs
== ['RA', 'RB', '', 'RT', '', 'CR0']:
558 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
559 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
560 res
['2'] = 's:RB' # RB: Rsrc1_EXTRA3
561 elif regs
== ['RA', '', 'RS', 'RA', '', 'CR0']:
562 res
['0'] = 'd:RA;d:CR0' # RA,CR0: Rdest1_EXTRA3
563 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA3
564 res
['2'] = 's:RS' # RS: Rsrc1_EXTRA3
568 elif value
== 'RM-2P-2S1D':
569 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
570 if insn_name
.startswith('mt'): # mtcrf
571 res
['0'] = 'd:CR' # CR: Rdest1_EXTRA2
572 res
['1'] = 's:RS' # RS: Rsrc1_EXTRA2
573 res
['2'] = 's:CR' # CR: Rsrc2_EXTRA2
577 elif value
== 'RM-1P-3S1D':
578 res
['Etype'] = 'EXTRA2' # RM EXTRA2 type
579 if regs
== ['RA', 'RB', 'RT', 'RT', '', 'CR0']:
580 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA2
581 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
582 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
583 res
['3'] = 's:RT' # RT: Rsrc3_EXTRA2
584 elif insn_name
== 'isel':
585 res
['0'] = 'd:RT' # RT: Rdest1_EXTRA2
586 res
['1'] = 's:RA' # RA: Rsrc1_EXTRA2
587 res
['2'] = 's:RB' # RT: Rsrc2_EXTRA2
588 res
['3'] = 's:BC' # BC: Rsrc3_EXTRA2
590 res
['0'] = 'd:FRT;d:CR1' # FRT, CR1: Rdest1_EXTRA2
591 res
['1'] = 's:FRA' # FRA: Rsrc1_EXTRA2
592 res
['2'] = 's:FRB' # FRB: Rsrc2_EXTRA2
593 res
['3'] = 's:FRC' # FRC: Rsrc3_EXTRA2
595 elif value
== 'RM-1P-1D':
596 res
['Etype'] = 'EXTRA3' # RM EXTRA3 type
597 if insn_name
== 'svstep':
598 res
['0'] = 'd:RT;d:CR0' # RT,CR0: Rdest1_EXTRA3
599 if insn_name
== 'fmvis':
600 res
['0'] = 'd:FRS' # FRS: Rdest1_EXTRA3
603 def process_csvs(format
):
605 print("# Draft SVP64 Power ISA register 'profile's")
607 print("this page is auto-generated, do not edit")
608 print("created by http://libre-soc.org/openpower/sv_analysis.py")
611 (csvs
, csvs_svp64
, primarykeys
, bykey
, insn_to_csv
, insns
,
612 dictkeys
, immediates
) = read_csvs()
614 # mapping to old SVPrefix "Forms"
615 mapsto
= {'3R-1W-CRo': 'RM-1P-3S1D',
616 '2R-1W-CRio': 'RM-1P-2S1D',
617 '2R-1W-CRi': 'RM-1P-3S1D',
618 '2R-1W-CRo': 'RM-1P-2S1D',
620 '2R-1W': 'RM-1P-2S1D',
621 '1R-CRio': 'RM-2P-2S1D',
622 '2R-CRio': 'RM-1P-2S1D',
623 '2R-CRo': 'RM-1P-2S1D',
625 '1R-1W-CRio': 'RM-2P-1S1D',
626 '1R-1W-CRo': 'RM-2P-1S1D',
627 '1R-1W': 'RM-2P-1S1D',
628 '1R-1W-imm': 'RM-2P-1S1D',
629 '1R-CRo': 'RM-2P-1S1D',
630 '1R-imm': 'RM-1P-1S',
631 '1W-CRo': 'RM-1P-1D',
633 '1W-imm': 'RM-1P-1D',
634 '1W-CRi': 'RM-2P-1S1D',
635 'CRio': 'RM-2P-1S1D',
636 'CR=2R1W': 'RM-1P-2S1D',
640 'LDST-2R-imm': 'LDSTRM-2P-2S',
641 'LDST-2R-1W-imm': 'LDSTRM-2P-2S1D',
642 'LDST-2R-1W': 'LDSTRM-2P-2S1D',
643 'LDST-2R-2W': 'LDSTRM-2P-2S1D',
644 'LDST-1R-1W-imm': 'LDSTRM-2P-1S1D',
645 'LDST-1R-2W-imm': 'LDSTRM-2P-1S2D',
646 'LDST-3R': 'LDSTRM-2P-3S',
647 'LDST-3R-CRo': 'LDSTRM-2P-3S', # st*x
648 'LDST-3R-1W': 'LDSTRM-2P-2S1D', # st*x
650 print("# map to old SV Prefix")
652 print('|internal key | public name |')
653 print('|----- | ---------- |')
654 for key
in primarykeys
:
655 name
= keyname(dictkeys
[key
])
656 value
= mapsto
.get(name
, "-")
657 print(tformat([name
, value
+ " "]))
663 print(tformat(tablecols
) + " imms | name |")
664 print(tformat([" - "] * (len(tablecols
)+2)))
666 # print out the keys and the table from which they're derived
667 for key
in primarykeys
:
668 name
= keyname(dictkeys
[key
])
669 row
= tformat(dictkeys
[key
].values())
670 imms
= list(immediates
.get(key
, ""))
672 row
+= " %s | " % ("/".join(imms
))
673 row
+= " %s |" % name
678 # print out, by remap name, all the instructions under that category
679 for key
in primarykeys
:
680 name
= keyname(dictkeys
[key
])
681 value
= mapsto
.get(name
, "-")
682 print("## %s (%s)" % (name
, value
))
684 print(tformat(['CSV', 'opcode', 'asm', 'flags', 'form']))
685 print(tformat(['---', '------', '---', '-----', '----']))
693 # for fname, csv in csvs.items():
696 # for insn, row in insns.items():
699 print("# svp64 remaps")
700 svp64
= OrderedDict()
701 # create a CSV file, per category, with SV "augmentation" info
702 # XXX note: 'out2' not added here, needs to be added to CSV files
703 # KEEP TRACK OF THESE https://bugs.libre-soc.org/show_bug.cgi?id=619
704 csvcols
= ['insn', 'mode', 'CONDITIONS', 'Ptype', 'Etype',]
705 csvcols
+= ['0', '1', '2', '3']
706 csvcols
+= ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out'] # temporary
707 for key
in primarykeys
:
708 # get the decoded key containing row-analysis, and name/value
711 value
= mapsto
.get(name
, "-")
712 if value
== 'non-SV':
715 # print out svp64 tables by category
716 print("* **%s**: %s" % (name
, value
))
718 # store csv entries by svp64 RM category
719 if value
not in svp64
:
726 # for idx in range(len(row)):
727 # if row[idx] == 'NONE':
729 # get the instruction
733 insn
= insns
[(insn_name
, condition
)]
735 # start constructing svp64 CSV row
737 res
['insn'] = insn_name
738 res
['CONDITIONS'] = condition
739 res
['Ptype'] = value
.split('-')[1] # predication type (RM-xN-xxx)
740 # get whether R_xxx_EXTRAn fields are 2-bit or 3-bit
741 res
['Etype'] = 'EXTRA2'
742 # go through each register matching to Rxxxx_EXTRAx
743 for k
in ['0', '1', '2', '3']:
745 # create "fake" out2 (TODO, needs to be added to CSV files)
746 # KEEP TRACK HERE https://bugs.libre-soc.org/show_bug.cgi?id=619
748 if insn
['upd'] == '1': # LD/ST with update has RA as out2
751 # set the SVP64 mode to NORMAL, LDST, BRANCH or CR
752 crops
= ['mfcr', 'mfocrf', 'mtcrf', 'mtocrf',
755 if value
.startswith('LDST'):
757 elif insn_name
.startswith('bc'):
759 elif insn_name
.startswith('cr') or insn_name
in crops
:
763 # create a register profile list (update res row as well)
764 regs
= regs_profile(insn
, res
)
766 #print("regs", insn_name, regs)
767 extra_classifier(insn_name
, value
, name
, res
, regs
)
770 # for k in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
772 # if res['0'] != 'TODO':
774 if k
== 'CONDITIONS':
776 if res
[k
] == 'NONE' or res
[k
] == '':
778 svp64
[value
].append(res
)
779 # also add to by-CSV version
780 csv_fname
= insn_to_csv
[insn_name
]
781 csvs_svp64
[csv_fname
].append(res
)
785 # now write out the csv files
786 for value
, csv
in svp64
.items():
789 from time
import sleep
790 print ("WARNING, filename '-' should NOT exist. instrs missing")
791 print ("TODO: fix this (and put in the bugreport number here)")
793 # print out svp64 tables by category
794 print("## %s" % value
)
796 cols
= csvcols
+ ['out2']
798 print(tformat([" - "] * (len(cols
))))
806 #csvcols = ['insn', 'Ptype', 'Etype', '0', '1', '2', '3']
807 write_csv("%s.csv" % value
, csv
, csvcols
+ ['out2'])
809 # okaaay, now we re-read them back in for producing microwatt SV
811 # get SVP64 augmented CSV files
812 svt
= SVP64RM(microwatt_format
=True)
813 # Expand that (all .csv files)
814 pth
= find_wiki_file("*.csv")
816 # Ignore those containing: valid test sprs
817 for fname
in glob(pth
):
818 #print("post-checking", fname)
819 _
, name
= os
.path
.split(fname
)
826 if fname
.endswith('sprs.csv'):
828 if fname
.endswith('minor_19_valid.csv'):
832 svp64_csv
= svt
.get_svp64_csv(fname
)
834 csvcols
= ['insn', 'mode', 'Ptype', 'Etype']
835 csvcols
+= ['in1', 'in2', 'in3', 'out', 'out2', 'CR in', 'CR out']
837 if format
is Format
.VHDL
:
838 # and a nice microwatt VHDL file
839 file_path
= find_wiki_file("sv_decode.vhdl")
840 elif format
is Format
.BINUTILS
:
841 file_path
= find_wiki_file("binutils.c")
843 with
open(file_path
, 'w') as stream
:
844 output(format
, svt
, csvcols
, insns
, csvs_svp64
, stream
)
847 def output_autogen_disclaimer(format
, stream
):
849 "this file is auto-generated, do not edit",
850 "http://libre-soc.org/openpower/sv_analysis.py",
851 "part of Libre-SOC, sponsored by NLnet",
853 for line
in format
.wrap_comment(lines
):
859 def output(format
, svt
, csvcols
, insns
, csvs_svp64
, stream
):
873 def svp64_canonicalize(item
):
875 value
= value
.lower().replace("-", "_")
878 csvs_svp64_canon
= dict(map(svp64_canonicalize
, csvs_svp64
.items()))
881 output_autogen_disclaimer(format
, stream
)
884 for line
in format
.declarations(csvs_svp64_canon
.keys(), lens
):
885 stream
.write(f
"{line}\n")
888 sv_cols
= ['sv_in1', 'sv_in2', 'sv_in3', 'sv_out', 'sv_out2',
889 'sv_cr_in', 'sv_cr_out']
890 fullcols
= csvcols
+ sv_cols
892 entries_svp64
= defaultdict(list)
893 for (value
, csv
) in filter(lambda kv
: kv
[0] in lens
, csvs_svp64_canon
.items()):
895 insn
= str(entry
['insn'])
896 condition
= str(entry
['CONDITIONS'])
897 mode
= str(entry
['mode'])
898 sventry
= svt
.svp64_instrs
.get(insn
, None)
899 if sventry
is not None:
900 sventry
['mode'] = mode
901 op
= insns
[(insn
, condition
)]['opcode']
902 # binary-to-vhdl-binary
903 if op
.startswith("0b"):
904 op
= "2#%s#" % op
[2:]
906 for colname
in csvcols
[1:]:
908 # zero replace with NONE
912 re
= re
.replace("1P", "P1")
913 re
= re
.replace("2P", "P2")
915 #print("sventry", sventry)
916 for colname
in sv_cols
:
920 re
= sventry
[colname
]
922 entries_svp64
[value
].append((op
, insn
, row
))
924 for line
in format
.definitions(entries_svp64
, fullcols
):
925 stream
.write(f
"{line}\n")
930 os
.environ
['SILENCELOG'] = '1'
931 parser
= argparse
.ArgumentParser()
932 parser
.add_argument("-f", "--format",
933 type=Format
, choices
=Format
, default
=Format
.VHDL
,
934 help="format to be used (binutils or VHDL)")
935 args
= parser
.parse_args()
936 process_csvs(args
.format
)
939 if __name__
== '__main__':
940 # don't do anything other than call main() here, cuz this code is bypassed
941 # by the sv_analysis command created by setup.py